Содержимое скопированной структуры изменяется после того, как временная структура свободна - PullRequest
0 голосов
/ 29 апреля 2018

Я делаю простую программу базы данных, чтобы узнать о структурах и двоичных деревьях. Я создал глобальную структуру Student с 3 полями: имя, фамилия, возраст и написал функцию для приема 3 пользовательских входных данных (например, в виде строк in_fname, in_sname и int in_age) и поместите их во временную структуру new, планируя скопировать их в соответствующее местоположение основного дерева. После ввода пользовательских данных для первой записи у меня есть:

struct Student *new;
new = (Student *) malloc (sizeof(struct Student));
strcpy (new->fname, in_fname);
strcpy (new->sname, in_sname);
new->age = in_age;
new->left = new->right = NULL;
printf("Contents of new is '%s', '%s', '%d'.\n",new->fname, new->sname, new->age);

student_tree = new  /* wanting to copy the new student as the first entry in the tree*/

Теперь, когда я

print("Contents of structure is '%s', '%s', '%d'.\n",student_tree->fname, student_tree->sname, student_tree->age);

Я получаю правильные записи, указывая, что копия сработала, но когда я

free(new)
print("Contents of structure is '%s', '%s', '%d'.\n",student_tree->fname, student_tree->sname, student_tree->age);

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

Может кто-нибудь объяснить, что мне не хватает? Не обязательно хотеть фиксированный код, просто чтобы понять, почему меняется содержимое структуры в дереве, когда исчезла вещь, из которой я его скопировал, и как я могу ее постоянно копировать.

Большое спасибо,

* * Ш тысячу двадцать-один

Ответы [ 3 ]

0 голосов
/ 29 апреля 2018

Выполнение free(now) и последующий доступ к now - это все равно, что выключить двигатель и задаться вопросом, почему ваш автомобиль больше не ускоряется при нажатии педали газа.

Обратите внимание, что

student_tree = new

is not копирование содержимого, куда указывает new, это просто назначение другой указатель на местоположение, на которое указывает new. Что у вас здесь это просто 2 указателя, которые указывают на одно и то же место. Если вы сделаете free(now), то оба указателя указывают на свободную память и, конечно, вы не можете получить доступ к память с одним из указателей (new или student_tree).

Если вы хотите освободить new, то вам нужно сделать копию памяти. Это может покончим с memcpy вот так:

struct Student copy;
memcpy(&copy, new, sizeof copy);

но в зависимости от самой структуры (содержит ли она указатель или массив), memcpy может быть неправильным решением.

Сейчас трудно дать вам правильный ответ, потому что есть так много информация отсутствует у вас, например, как struct Person выглядит, как вставить функции выглядят так, как вы их называете и т. д.

Также

strcpy (new->fname, in_fname);
strcpy (new->sname, in_sname);

Это может быть опасно, опять же, вы не предоставляете нам достаточно информации, но если вы не будьте осторожны, вы можете переполнить буферы. Я полагаю из вашего кода, что fname и sname являются массивами char. В этом случае я бы использовал strncpy вместо этого, потому что реальная длина in_fname и in_sname может быть неизвестна и / или может быть больше, чем могут хранить fname и sname. Так в общем то более надежное решение будет:

strncpy(new->fname, in_fname, sizeof new->fname);
new->fname[sizeof(new->fname) - 1] = '\0';

strncpy(new->sname, in_sname, sizeof new->sname);
new->sname[sizeof(new->sname) - 1] = '\0';
0 голосов
/ 30 апреля 2018

В опубликованном вами коде new является указателем и содержит не структуру Student, а адрес в памяти для Student. В C по большей части данные могут храниться в памяти стека вашей программы или кучи памяти. Память стека управляется, но становится недействительной, когда вы выходите из области действия, в то время как память кучи сохраняется в вашей программе. malloc() выделяет столько памяти кучи, сколько вы указали (в данном случае этого достаточно для Student), и возвращает указатель на выделенную память. Поскольку память, на которую указывает new, сохраняется в вашей программе, вы должны вручную освободить память с помощью free().

Важным для понимания указателей является эта строка:

student_tree = new;

Не зная, какого типа student_tree, сложно сказать, что происходит, но давайте предположим, что где-то выше существует объявление struct Student *student_tree;. Если это так, то обе переменные - это указатели, выделенные в вашей памяти стека, и student_tree присваивается значение new, которое является адресом памяти, который вы выделили с помощью malloc().

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

0 голосов
/ 29 апреля 2018

Это потому, что student_tree и new являются указателями. Когда вы присваиваете new для student_tree, копирование не выполняется, оно просто указывает student_tree на ту же память. Когда вы вызываете free(new), он освобождает память, на которую указывает new, которая также является памятью, на которую указывает student_tree, так что это понятно мусор.

Вот код, который будет делать фактическую копию:

struct Student* student_tree = malloc(sizeof(struct Student));
*student_tree = *new;

Здесь я создаю указатель student_tree, выделяю память для хранения struct Student и, наконец, помещаю содержимое памяти, на которое указывает new, в память, на которую указывает student_tree.

...