Reputation: 531
I would like to allocate memory for a buffer that will contain, via memcpy in the future, a struct that contains a pointer that has been previously dynamically allocated memory.
That is, I have a struct
struct test_struct {
int num;
char *values;
};
Where test_struct.values
contains num
amount of strings of length LENGTH
. I know I can't get the size of memory a pointer has been allocated, so I just keep track of it via num
. What is the easiest/cleanest way of getting the size of this struct?
The only solution I can come up with is something like
buf = malloc(sizeof(test_struct) + (num * LENGTH));
But I'm new to this low-level memory management stuff, so there might be something better.
Upvotes: 1
Views: 2775
Reputation: 4357
If you would like to memcpy two structs then the memory in both of them must be continuous. But you would have to determine num
beforehand.
struct test_struct {
int num;
char ** values;
} * TestStruct;
int _num = 0;
// find _num
TestStruct = malloc (sizeof (struct test_struct) + (sizeof(char*) * _num) + (LENGTH * _num));
TestStruct->num = _num;
TestStruct->values = &TestStruct + sizeof (struct test_struct);
for (int i = 0; i < _num; i++){
TestStruct->values[i] = &TestStruct + sizeof (struct test_struct) + (i * LENGTH);
}
The reason I changed char * to char ** is because using char * it becomes harder to access the strings after the first (I'm assuming they're null terminated). Also, after calling memcpy, you must update all the string pointers in the new struct.
To memcpy you would do this:
memcpy (buf, TestStruct->values[0], LENGTH * TestStruct->num);
But in buf, however, you would only see the first string (unless your strings are not null-terminated). You would have to increment the pointer after every null terminated character until you know, with num
, that you've reached the end of the buffer.
Now that I understand more of the context of your request, consider the following.
If you're using UDP packets, you should send the data in one packet so that it arrives in the order you expect. When more than one packet is sent, it may arrive out of order. Because of this, you need to make sure the size of the data is <= 512 bytes - which is the maximum size of a UDP packet. Also, you need to make sure all the data is in contiguous memory. I'm going to assume you have your data already in the struct you've provided in this example:
// this function puts the struct in contiguous memory
int PrepareBuffer (struct test_struct TestStruct, char ** buffer){
char * cast = (char *) &TestStruct->num;
* buffer = malloc ((TestStruct->num * LENGTH) + sizeof (int));
for (int i = 0; i < sizeof (int); i++) *buffer[i] = cast[i];
for (int i = 0; i < (TestStruct->num * LENGTH); i++) *buffer[i + sizeof (int)] = TestStruct->values[i];
return 0;
}
You will have to implement another function on the receiving end that maps the buffer to struct test_struct
. Also, I have omitted error checking for clarity. You should check for how big the packet is going to be before to allocate memory (it has to be <= 512). You should also check to make sure malloc returns a none-null pointer.
Upvotes: 4
Reputation: 3484
I'm assuming that you want to allocate memory for both the structure and the buffer that values points to. If so, this is correct. To point at the extra space, do buf->values = buf + 1;
(this is assuming you declare buf as struct test_struct buf;
Upvotes: 0
Reputation: 2842
You should only need to allocate 4 bytes (for the integer on 32 bit linux) and 4 bytes for the char * (in 32 bit. 64 is 8).
What you're really asking though, is how do I know how much memory I need to allocate to the region pointed to by char *value. You figure this out in the wya you're doing. Then set value to the location of buf. There's a comment blow me that is the correct way if you have multiple string, and you don't want to just jam them all together in that region and have to figure out which is which yourself.
Upvotes: 0