我不明白指针,地址和范围

时间:2016-04-24 10:53:43

标签: c pointers

以下是一段代码片段,我已经写过了,我正在努力解决我的打印问题。

在我的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 */
}

有人知道为什么会这样吗?任何建设性的评论/答案都表示赞赏。

我也很感激,如果下来的人会向我提供反馈,为什么他们发现我的问题不合适。

4 个答案:

答案 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。此外,不要忘记取消分配动态分配的任何内存:必须使用callocrealloc后释放任何分配有freestruct 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对象,这样我就可以延长函数调用时间