繁体   English   中英

我不了解指针,地址和范围

[英]I don't understand pointers, addresses and scopes

以下是我编写的代码段,目前正在打印中挣扎。

在我的主要方法中,我使用有效输入两次调用函数insertPoint ,例如: insertPoint(42); insertPoint(56); 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 */
}

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

如果下降者会向我提供反馈,我也将不胜感激,为什么他们认为我的问题不合适。

如果采用if (root == 0)分支,则root将指向struct point newRoot; 这是在if分支主体内部的堆栈上分配的。 newRoot结构在离开分支的主体和函数的主体之后(在您的情况下,在return value;之后)超出范围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 )。 另外,不要忘记释放动态分配的任何内存:使用malloccallocrealloc分配的任何内存都必须稍后使用free

您的代码具有未定义的行为,因为它允许在范围之外使用指向局部变量的指针。

它发生在这里:

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;
}

当然,在退出程序之前,您需要使用malloc free分配的malloc ,以避免内存泄漏。

您创建struct point newRoot; 在函数内部的堆栈上。 由于它在堆栈上,因此在退出此函数时将其销毁。 此后,任何使用其指针( *root )的操作都应给出未定义的结果。

您必须了解,堆栈超出范围时,堆栈中的内容会消失

所以

root = &newRoot;

这里newRoot在堆栈中。 函数结束newRoot结束-指针无效

使用malloc创建newRoot对象,这样我可以使函数调用的寿命更长

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM