Reputation: 2166
I want to parse a character buffer and store it in a data structure. The 1st 4 bytes of the buffer specifies the name, the 2nd four bytes specifies the length (n) of the value and the next n bytes specifies the value.
eg: char *buff = "aaaa0006francebbbb0005swisscccc0013unitedkingdom"
I want to extract the name and the value from the buffer and store it a data structure. eg: char *name = "aaaa" char *value = "france"
char *name = "bbbb"
char *value = "swiss"
After storing, I should be able to access the value from the data structure by using the name. What data structure should I use?
EDIT (from comment): I tried the following:
struct sample {
char string[4];
int length[4];
char *value; };
struct sample s[100];
while ( *buf ) {
memcpy(s[i].string, buf, 4);
memcpy(s[i].length, buf+4, 4);
memcpy(s[i].value, buf+8, s.length);
buf += (8+s.length);
}
Should I call memcpy thrice? Is there a way to do it by calling memcpy only once?
Upvotes: 2
Views: 7896
Reputation: 28900
I would do something like that: I will define a variable length structure, like this:
typedef struct {
char string[4];
int length[4];
char value[0] } sample;
now , while parsing, read the string and length into temporary variables. then, allocate enough memory for the structure.
uint32_t string = * ( ( uint32_t * ) buffer );
uint32_t length = * ( ( uint32_t * ) buffer + 4);
sample * = malloc(sizeof(sample) + length);
// Check here for malloc errors...
* ( (uint32_t *) sample->string) = string;
* ( (uint32_t *) sample->length) = length;
memcpy(sample->value, ( buffer + 8 ), length);
This approach, keeps the entire context of the buffer in one continuous memory structure. I use it all the time.
Upvotes: 1
Reputation: 12910
How about not using memcpy at all?
typedef struct sample {
char name[4];
union
{
char length_data[4];
unsigned int length;
};
char value[];
} sample_t;
const char * sample_data = "aaaa\6\0\0\0francebbbb\5\0\0\0swisscccc\15\0\0\0unitedkingdom";
void main()
{
sample_t * s[10];
const char * current = sample_data;
int i = 0;
while (*current)
{
s[i] = (sample_t *) current;
current += (s[i])->length + 8;
i++;
}
// Here, s[0], s[1] and s[2] should be set properly
return;
}
Now, you never specify clearly whether the 4 bytes representing the length contain the string representation or the actual binary data; if it's four characters that needs to run through atoi() or similar then you need to do some post-processing like
s[i]->length = atoi(s[i]->length_data)
before the struct is usable, which in turn means that the source data must be writeable and probably copied locally. But even then you should be able to copy the whole input buffer at once instead of chopping it up.
Also, please note that this relies on anything using this struct honors the length field rather than treating the value field as a null-terminated string.
Finally, using binary integer data like this is obviously architecture-dependent with all the implications that follows.
Upvotes: 2
Reputation: 13244
To expand on your newly provided info, this will work better:
struct sample {
char string[4];
int length;
char *value; };
struct sample s[100];
while ( *buf && i < 100) {
memcpy(s[i].string, buf, 4);
s[i].length = atoi(buf+4);
s[i].value = malloc(s[i].length);
if (s[i].value)
{
memcpy(s[i].value, buf+8, s[i].length);
}
buf += (8+s[i].length);
i++;
}
Upvotes: 2