#c
#c
Вопрос:
Допустим, у меня есть тип node_t
typedef struct node{
char* value;
struct node *next;
}node_t;
Когда я хочу создать новый указатель node_t с именем n1, я вызываю malloc
node_t *n1 = malloc(sizeof(node_t));
Теперь я хочу получить доступ и использовать другие поля внутри n1 : value и далее, должен ли я снова вызывать malloc для этих указателей, вот так:
n1->value = malloc(sizeof(char));
n1->next = malloc(sizeof(node_t));
Или самый первый вызов malloc() при создании n1 уже сделал все это?
Комментарии:
1.
malloc
выделяет новоеnode_t
, и ничего больше. Он не инициализирует элементы выделенногоstruct
и, конечно же, не выделяет память для любых указателей, которые являются членамиstruct
.2.
sizeof(char)
всегда равно 1 [по определению]. Итак, не используйте это. Итак, как правило, вы хотели бы (например)char str[] = "A string to store"; n1->value = strdup(str);
И, опять же, при воссоздании данного узла (например)n1
вы не создаетеnext
узел одновременно. Это происходит позже [обычно, при последующем вызове функции create]
Ответ №1:
должен ли я снова вызывать malloc для этих указателей
Это зависит от того, как вы хотите использовать эти элементы.
Когда вы выполняете malloc a, node_t
вы получаете память для хранения 1) char
указателя и 2) node_t
указателя. Вы можете установить эти указатели так, чтобы они указывали на другие существующие объекты. Но вы также можете установить эти указатели так, чтобы они указывали на новые (динамически распределяемые) объекты.
Пример 1
node_t *n1 = malloc(sizeof *n1);
assert(n1 != NULL);
n1->value = "Hello world";
n1->next = NULL;
node_t *n2 = malloc(sizeof *n2);
assert(n2 != NULL);
n2->value = "Have fun";
n2->next = NULL;
n1->next = n2; // Create a linked list
В этом примере нет прямого malloc для каких-либо членов node_t
. Члены просто настроены так, чтобы указывать на другие объекты.
Пример 2
node_t *n1 = malloc(sizeof *n1);
assert(n1 != NULL);
n1->value = "Hello world";
n1->next = malloc(sizeof *n1->next);
assert(n1->next != NULL);
n1->next->value = "Have fun";
n1->next->next = NULL;
Этот пример приводит к тому же, что и первый пример. Это просто написано немного по-другому, т.Е. next
указатель n1
присваивается для указания на новый malloc node_t
вместо того, чтобы иметь n2
объект.
Пример 3
char *str1= "Hello world";
char *str2= "Have fun";
node_t *n1 = malloc(sizeof *n1);
assert(n1 != NULL);
n1->value = malloc(1 strlen(str1));
strcpy(n1->value, str1); // Copy the string
n1->next = malloc(sizeof *n1->next);
assert(n1->next != NULL);
n1->next->value = malloc(1 strlen(str2));
strcpy(n1->next->value, str2); // Copy the string
n1->next->next = NULL;
Здесь value
указатель устанавливается так, чтобы указывать на новый объект malloc, и в этот объект помещается копия строки.
Итак, повторяю — хотите ли вы использовать память malloc для членов, зависит от того, как вы хотите использовать структуру.
Комментарии:
1. Не используйте
assert
для проверки возвращаемого значенияmalloc
.assert
предназначен для проверки ошибок программирования во время отладки, а не для ошибок во время выполнения. Для c-реализации совершенно нормально определятьassert
как не-операцию.