Вопрос о передаче указателя на структуру в C функции? - PullRequest
2 голосов
/ 16 апреля 2010

Ниже я написал примитивный односвязный список на C. Функция «addEditNode» ДОЛЖНА получать указатель по значению, что, как я предполагаю, означает, что мы можем редактировать данные указателя, но не можем указывать на что-то другое. Если я выделю память, используя malloc в «addEditNode», когда функция вернется, смогу ли я увидеть содержимое first-> next? Второй вопрос: нужно ли мне сначала освободить-> затем, или только сначала я должен освободиться? Я сталкиваюсь с ошибками сегментации в Linux.

#include <stdio.h>
#include <stdlib.h>

typedef struct list_node list_node_t;

struct list_node
{ 
  int value;
  list_node_t *next;
};

void addEditNode(list_node_t *node)
{
   node->value = 10;
   node->next =  (list_node_t*) malloc(sizeof(list_node_t));
   node->next->value = 1;
   node->next->next = NULL; 
}

int main()
{
  list_node_t *first = (list_node_t*) malloc(sizeof(list_node_t));

  first->value = 1;
  first->next = NULL;

  addEditNode(first);

  free(first);

  return 0;
}

Ответы [ 4 ]

2 голосов
/ 16 апреля 2010

.. означает, что мы можем редактировать данные указателя, но не можем указать на что-то еще ...

Да

Если я выделю память с помощью malloc в "addEditNode", когда функция вернется, могу ли я увидеть содержимое first-> next?

Да. Память выделяется в куче, поэтому вы можете получить к ней доступ. Обратите внимание, что вы по-прежнему несете ответственность за освобождение памяти.

Второй вопрос: нужно ли мне сначала освободить-> затем, или только сначала я должен освободиться?

Да. Вы должны освободить всю память, выделенную в куче.


Хотя, есть утечка памяти (first->next не free d), но вы, вероятно, не должны получить ошибку сегмента.

Примечание:

node->next =  (list_node_t*) malloc(sizeof(list_node_t));

Явное приведение не требуется в случае malloc в C (требуется в C ++). Следующее просто отлично.

node->next = malloc(sizeof(list_node_t));
1 голос
/ 16 апреля 2010

Если я выделю память с помощью malloc в «addEditNode», когда функция вернется, смогу ли я увидеть содержимое first->next?

Да, вы можете увидеть это в main.

Второй вопрос: нужно ли мне сначала освободить-> затем, или мне нужно освободить только сначала?

Вы также должны освободить first->next, в противном случае вы получите утечку памяти.

Ошибка сегментации, которую вы можете получить, если попытаетесь разыменовать first после ее удаления.

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

0 голосов
/ 16 апреля 2010

Указатель - это целое число, которое обозначает адрес в памяти. Детали «памяти» здесь не указаны; просто знайте, что указатель содержит число, которое является абсолютным байтом в адресном пространстве вашей программы.

Поэтому, когда вы передаете указатель, вы передаете адрес. Таким образом, редактируя данные по адресу, вы делаете свои изменения видимыми вне локальной функции. Так что да, вы увидите изменения, сделанные в addEditNode () в main ().

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

0 голосов
/ 16 апреля 2010

Во-первых, да, вы можете «увидеть» содержимое first->next, когда функция вернется. node->next - это значение в структуре, на которое указывает node, что указывает на то же место, что и first. При передаче указателя first по значению копируется только сам указатель, а не вся структура, на которую он указывает. Другими словами, *first в main - это те же данные, что и *node в addEditNode (не копия), просто каждая функция имеет другой указатель (один называется * 1012). * и тот, который называется node), который указывает на эту единственную структуру.

Во-вторых, да, вы также должны освободить node->next, иначе у вас будет утечка. Когда вы освобождаете указатель на структуру, он не рекурсивно освобождает указатели, которые являются членами этой структуры.

Однако я не вижу в этом коде ничего неправильного или способного вызвать ошибку сегментации (утечка не вызовет ошибки сегмента).

...