以下是一段代码片段,我已经写过了,我正在努力解决我的打印问题。
在我的main方法中,我使用有效输入调用函数insertPoint
两次,例如:insertPoint(42); insertPoint(56);
并获得以下输出:
A.1 42
B.3 2686700
在B.3但我希望它也会返回值42,但事实并非如此。我假设2686700指的是内存中的某个地址。
#include <stdio.h>
#include <stdlib.h>
struct point {
int value;
struct point* next;
};
struct point *root;
int insertPoint(int value) {
// Graph is empty, set new root
if(root == 0){
struct point newRoot;
newRoot.value = value;
root = &newRoot;
(*root).value = value;
printf("A.1 %d \n", (*root).value); // "A.1 42"
return value;
}
printf("B.3 %d \n", (*root).value); // "B.3 2686700"
/* rest of code here; irrelevant since related variables are not changed */
}
有人知道为什么会这样吗?任何建设性的评论/答案都表示赞赏。
我也很感激,如果下来的人会向我提供反馈,为什么他们发现我的问题不合适。
答案 0 :(得分:5)
如果采用if (root == 0)
分支,root
将指向在struct point newRoot;
分支主体内的堆栈上分配的if
。在newRoot
语句之后离开分支的主体和函数体之后,return value;
结构超出了范围。但是,全局指针变量root
将继续指向内存中的位置(堆栈上)。该位置的堆栈内存的内容很可能会被其他一些代码覆盖,因此从该位置读取point
(成员)值(例如通过root
指针)将导致未定义的行为,这就是为什么你得到这样的结果。
您可能想要动态分配新根,例如:
if(root == 0) {
root = (point *) malloc(sizeof(point));
root->value = value;
root->next = NULL;
printf("A.1 %d \n", root->value); // "A.1 42"
return value;
}
不要忘记设置next
指针,因为它不会默认为NULL
(除非malloc
代替calloc
使用next
进行零初始化返回的内存,在大多数平台上有效地使NULL
的值等于malloc
。此外,不要忘记取消分配动态分配的任何内存:必须使用calloc
在realloc
后释放任何分配有free
,struct point newRoot;
或*root
的内存。
答案 1 :(得分:3)
您的代码具有未定义的行为,因为它允许在范围之外使用指向局部变量的指针。
它发生在这里:
struct point newRoot;
...
root = &newRoot;
问题在于,一旦函数到达}
关闭if
语句,root
就会失效。任何解除引用都是未定义的行为。因此当你这样做时
printf("B.3 %d \n", (*root).value);
您访问由无效指针指向的内存。
幸运的是,对此问题的修复很简单:使用malloc
而不是newRoot
为链表元素分配内存:
if(root == 0){
root = malloc(sizeof(struct point));
root->value = value;
printf("A.1 %d \n", (*root).value); // "A.1 42"
return value;
}
当然,在退出程序之前,您需要free
使用malloc
分配的内存,以避免内存泄漏。
答案 2 :(得分:2)
您在函数内的堆栈上创建{{1}}。因为,它在堆栈上,它在退出此函数时被销毁。任何使用它的指针({{1}})都应该在此之后给出未定义的结果。
答案 3 :(得分:2)
你必须明白,当它超出范围时,堆栈上的东西会消失
SO
root = &newRoot;
此处newRoot
位于堆栈中。函数结束 - newRoot
结束 - 因此指针无效
使用malloc
创建newRoot
对象,这样我就可以延长函数调用时间