Reputation: 4377
In a C (ANSI) program I have a struct defined as:
typedef struct Contacts {
char * name;
char * email;
char * phone;
struct Contacts *next;
} aContact;
aContact *paContact;
Based on the length of the data that I am about to store, is it possible to allocated memory as (Option 1):
paContact = (struct Contacts *) malloc(sizeof (struct Contacts) +strlen(theName) + strlen(theEmail) + strlen(thePhone) + 3);
and then do something like (pseudocode):
paContact->name = paContact;
paContact->email = paContact + strlen(name) + 1;
paContact->phone = paContact->email + strlen(email) + 1;
Or do I have to allocate memory for each member individually as (Option 2):
paContact->name = (char*) malloc(sizeof (char)*strlen(name) + 1);
paContact->email = (char*) malloc(sizeof (char)*strlen(email) + 1);
paContact->phone = (char*) malloc(sizeof (char)*strlen(phone) + 1);
If Option 1 is not possible, what would be the proper way to keep track of all the allocated pieces of memory so that I could eventually free them?
Thank you!
Upvotes: 2
Views: 71
Reputation: 753605
You can use either technique. If you might need to edit the fields after creating the structure, then separate allocations are probably more appropriate. If there'll be no need to edit the fields, then a single allocation only requires a single deallocation — and also reduces the fragmentation of memory. There is some overhead for each allocation.
If you use the single allocation, you'll need to fix the assignments. This code doesn't check the memory allocations, but should.
size_t len_name = strlen(theName);
size_t len_email = strlen(theEmail);
size_t len_phone = strlen(thePhone);
aContact *paContact = malloc(sizeof(*paContact) + len_name + len_email + len_phone + 3);
char *data = (char *)paContact + sizeof(*paContact);
paContact->name = data;
strcpy(paContact->name, theName);
data += len_name + 1;
paContact->email = data;
strcpy(paContact->email, theEmail);
data += len_email + 1;
paContact->phone = data;
strcpy(paContact->phone, thePhone);
paContact->next = NULL;
It might, however, be easier to use POSIX strdup()
:
aContact *paContact = malloc(sizeof(*paContact));
paContact->name = strdup(theName);
paContact->email = strdup(theEmail);
paContact->phone = strdup(thePhone);
paContact->next = NULL;
If necessary, you can write a surrogate for strdup()
very easily:
char *str_dup_surrogate(const char *str)
{
size_t len = strlen(str) + 1;
char *result = malloc(len);
if (result != NULL)
memmove(result, str, len);
return result;
}
Note that the name str_dup_surrogate()
avoids the future directions for the C library specified in C11 §7.31.13 String handling <string.h>
. I'd be tempted to shorten it to str_dup()
, which likewise is a user-definable name.
Upvotes: 3