Динамическое выделение структуры struct C и доступ к членам на основе структуры памяти - PullRequest
2 голосов
/ 12 мая 2019

В программе на C (ANSI) у меня есть структура, определенная как:

typedef struct Contacts {
    char * name;
    char * email;
    char * phone;
    struct Contacts *next;
} aContact;
aContact *paContact;

На основании длины данных, которые я собираюсь сохранить, возможно ли выделить память как (Вариант 1):

paContact = (struct Contacts *) malloc(sizeof (struct Contacts) +strlen(theName) + strlen(theEmail) + strlen(thePhone) + 3);

и затем выполните что-то вроде (псевдокод):

paContact->name = paContact;
paContact->email = paContact + strlen(name) + 1;
paContact->phone = paContact->email + strlen(email) + 1;

Или мне нужно выделять память для каждого элемента индивидуально, как (вариант 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);

Если вариант 1 невозможен, каким будет правильный способ отслеживать все выделенные фрагменты памяти, чтобы я мог в конечном итоге освободить их?

Спасибо!

1 Ответ

3 голосов
/ 12 мая 2019

Вы можете использовать любую технику.Если вам, возможно, потребуется отредактировать поля после создания структуры, то, вероятно, более уместны отдельные распределения.Если нет необходимости редактировать поля, то для одного выделения требуется только одно освобождение, а также уменьшается фрагментация памяти.Для каждого выделения есть некоторые накладные расходы.

Если вы используете одно распределение, вам нужно будет исправить назначения.Этот код не проверяет выделение памяти, но должен.

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;

Однако может быть проще использовать POSIX strdup():

aContact *paContact = malloc(sizeof(*paContact));
paContact->name  = strdup(theName);
paContact->email = strdup(theEmail);
paContact->phone = strdup(thePhone);
paContact->next  = NULL;

При необходимости вы можете очень легко написать суррогат для strdup():

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;
}

Обратите внимание, что имя str_dup_surrogate() избегает будущих указаний для библиотеки C, указанной в C11 §7.31.13Обработка строк <string.h>.Я бы соблазнился сократить его до str_dup(), которое также является определяемым пользователем именем.

...