C динамически выделять тип структуры

#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 только для указателей, поэтому в основном я должен реализовать это с помощью указателя