#c #struct #dynamic-memory-allocation
Вопрос:
У меня есть структура, которая определяется следующим образом
typedef struct{ int year; char* name; int id; }person;
Как мне динамически выделить объект person и вставить в него свои данные? Мои данные показаны, как показано ниже
int personYear = 20; int personId = 12345678; char* personName = "firstname lastname";
Я знаю, что для декларации я могу сделать
person* p = (person*) malloc(sizeof(person)); p-gt;year = personYear; p-gt;id = personId;
Но после этого, как мне сделать вставку для char* person?
Нужно ли мне перераспределять пространство для хранения памяти?
// my thought p-gt;name = (char*) malloc (sizeof(char)); int counter = 0; while (*personName != '') { counter ; name = (char*) realloc (name, counter 1) // hold 1 more byte *(name counter) = ''; //make sure intialize the value *(name counter-1) = *personName; personName ; } //what's next?
Что действительно сбивает с толку, так это то, что struct имеет выравнивание памяти на C, и во время выполнения наша программа не знает, сколько байтов будет содержать это имя -gt;, нужно ли нам продолжать перераспределять пространство памяти для самой структуры? как правильно это сделать?
Комментарии:
1. Сделайте шаг назад; сделайте глубокий вдох; что вы на самом деле хотите, чтобы компьютер делал ?
person-gt;name
это указатель. Это означает, что он содержит адрес (т. е. Указывает на) чего-то другого. На что бы вы хотели, чтобы это указывало?2. Не связано: Вместо
person* p = (person*) malloc(sizeof(person));
того, что вы можете сделатьperson* p = malloc(sizeof *p);
— вам не нужно приводить, и использованиеsizeof
разыменованного указателя делает это немного более понятным (по мнению многих людей).3.Вам не нужно перераспределять пространство для строки по одному символу за раз. Просто укажите длину строки плюс 1:
p-gt;name = malloc(strlen(personName) 1);
strcpy(p-gt;name, personName);
. (Примечание 1:sizeof(char)
по определению равно 1, поэтому нет необходимости(strlen(personName) 1)
умножатьsizeof(char)
на вышеизложенное. Примечание 2: Нет необходимости вводить приведение возвращаемого значенияmalloc()
к другому типу указателя.) В некоторых реализациях библиотек естьstrdup()
функция (не входящая в стандарт C17) для выполнения вышеуказанного в одном:p-gt;name = strdup(personName);
.4. Я предлагаю использовать
strdup()
.
Ответ №1:
Одним из подходов к решению проблемы является использование гибкого элемента структуры. Он работает, помещая массив сразу после структуры. В этом случае это будет массив char
со строкой имени.
typedef struct { int year; int id; char name[]; // flexible member }person;
При выделении struct person
просто добавьте дополнительные strlen(name) 1
байты и скопируйте name
их туда.
person* make_person(int year, int id, char *name) { person *p = malloc(sizeof *p strlen(name) 1); if (!p) return NULL; // out of memory p-gt;id = id; p-gt;year = year; strcpy(p-gt;name, name); return p; }
Комментарии:
1. Не очень полезный подход, так как это значительно усложняет задачу, если вы когда-либо захотите увеличить размер строки, так как
realloc
может переместить память, если для ее увеличения нет места2. lt;string.hgt; запрещено, и невозможно узнать, сколько символов будет в именах участников во время компиляции
3. @randomNameGenerator,
lt;string.hgt;
это запрещено?! Значит, это какая-то садистская домашняя работа?4. @randomNameGenerator, единственный способ — реализовать
strlen()
себя. Это более или менее уже осознается циклом из вопроса:int counter = 0; while (*personName != '') { counter ; ... ; personName ; }
5. да, это программный hw только для указателей, поэтому в основном я должен реализовать это с помощью указателя