我正在制作一个简单的数据库程序来了解结构和二叉树。我创建了一个包含3个字段的全局结构Student
:名字,姓氏,年龄,并编写了一个函数来获取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
总是被破坏,包含垃圾。
有人可以解释我错过了什么吗?不必想要修复代码,只是为了理解为什么当我复制它的东西消失时树中结构的内容会发生变化,以及我如何能够永久地复制它。
非常感谢,
w ^
答案 0 :(得分:3)
因为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
指向的内存的内容放在{{1}指向的内存中1}}。
答案 1 :(得分:2)
执行free(now)
然后再访问now
就像关闭引擎然后想知道为什么当你踩下油门踏板时你的车不再加速。
请注意
student_tree = new
不复制new
指向的内容,它只是分配
另一个指向new
指向的位置的指针。你在这里有什么
只是2指针指向同一位置。如果你free(now)
,那么
两个指针都指向释放的内存,当然你无法访问
内存中有一个指针(new
和student_tree
)。
如果要释放new
,则必须复制内存。这个可以
完成这样的memcpy
:
struct Student copy;
memcpy(©, 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';
答案 2 :(得分:1)
您发布的代码straightMstart[i]
是一个指针,不包含结构new
,而是内存中Student
的地址。在C中,大部分数据可以存储在程序的堆栈内存或堆内存中。堆栈内存是受管理的,但在退出作用域时变为无效,而堆内存在整个程序中是持久的。 Student
分配尽可能多的堆内存(在这种情况下足够用于malloc()
)并返回指向已分配内存的指针。由于Student
指向的内存在整个程序中都是持久的,因此您必须使用new
手动释放内存。
理解指针很重要的是这一行:
free()
不知道student_tree = new;
的类型是什么,很难说出发生了什么,但让我们假设上面某处存在声明student_tree
。如果是这种情况,那么两个变量都是在堆栈内存中分配的指针,并且struct Student *student_tree;
被赋值为student_tree
,这是您使用new
分配的内存的地址。
因为两个变量现在指向相同的内存,所以当释放该内存时,指针都没有指向有效的内存。