为什么当我返回一个变量的内存地址而不是返回它的指针时会出现问题?

huangapple go评论81阅读模式
英文:

Why do I get a problem when I return a memory address of a variable as opposed to returning a pointer of it?

问题

这是我的代码:

struct Node* createNode(void* value) {
    struct Node node = {.val = value, .next = NULL};
    //struct Node* temp = &node;
    return &node;
}
struct Node:

struct Node {
    void* val;
    struct Node* next;
};

当我返回`&node`时,我收到一个错误消息,指出“返回了与局部变量'node'关联的堆栈内存的地址”

我尝试返回指向`node`的指针,问题就解决了。我明白`node`存储在堆栈内存中;但是,为什么当我返回`temp`时,我不会收到相同的错误,因为它也指向堆栈内存?
英文:

Here's my code:

    struct Node* createNode(void* value) {
        struct Node node = {.val = value, .next = NULL};
        //struct Node* temp = &node;
        return &node;
    }

struct Node:

    struct Node {
        void* val;
        struct Node* next;
    };

When I return &node, I get an error stating "address of stack memory associated with local variable 'node' returned"

I tried return a pointer pointing to node and the problem went away. I get that node is stored in the stack memory; however, why don't I get the same error when I return temp since it also points to the stack memory?

答案1

得分: 3

在C中,变量具有存储期限。

您的变量具有自动存储期,当您离开定义它的作用域时,它停止存在。当您尝试返回对它的引用(指针)时,该指针引用的对象不再存在。这会引发未定义的行为

为了防止引发UB,您的变量必须具有分配或静态存储期。

    struct Node* createNode(void* value) {
        struct Node *node = malloc(sizeof(*node));
        *node = (struct Node){.val = value, .next = NULL};
        return node;
    }

或者(不是一个最好的想法):

    struct Node* createNode(void* value) {
        static struct Node node;
        node = (struct Node){.val = value, .next = NULL};
        return &node;
    }

为什么当我返回temp时不会得到相同的错误,因为它也指向堆栈内存吗?

因为您没有返回对局部变量的引用,只返回指针temp的值。它可能包含或不包含对局部变量的引用。编译器需要分析您的代码。在这种简单情况下,如果您启用了优化(并且它迫使编译器深入分析),它会发出警告。但如果代码更复杂,编译器可能无法确定。

英文:

Variables in C have storage durations.

Your variable has automatic storage duration and it stops to exist when you leave the scope it was defined in. When you try to return reference (pointer) to it that pointer is referencing the object which does not exist anymore. It invokes undefined behaviour.

Your variable has to have allocated or static storage duration to prevent invoking UB

    struct Node* createNode(void* value) {
        struct Node *node = malloc(sizeof(*node));
        *node = (struct Node){.val = value, .next = NULL};
        return node;
    }

or (not a greatest idea):

    struct Node* createNode(void* value) {
        static struct Node node;
        node = (struct Node){.val = value, .next = NULL};
        return &node;
    }

> why don't I get the same error when I return temp since it also points
> to the stack memory?

Because you do not return the reference to the local variable, only the value of pointer temp. It may or may not contain a reference to the local variable. The compiler needs to analyze your code. In this trivial case if you enable optimizations (and it forces the compiler to take a deeper look) it will warn. But if the code is more complicated the compiler might not be able to determine it.

https://godbolt.org/z/Yj77MKqq4

答案2

得分: 1

The warning for this:

struct Node* createNode(void* value) {
    struct Node node = {.val = value, .next = NULL};
    return &node;
}

is because node is known to be on the stack, and the use of a pointer to that will lead to undefined behavior.

The lack of warning for this, which is what I think you are asking about:

struct Node* createNode(void* value) {
    struct Node node = {.val = value, .next = NULL};
    struct Node* temp = &node;
    return temp;
}

is that while it is clear that temp points to a structure on the stack, since it is a pointer (and not the address of a variable), it could conceivably point to something else.

For the compiler to detect the same problem, it would have to implement some kind of tracking of values that are probably not worth it in general terms.

In all cases, whether you get a warning/error or not, returning the address of an automatic variable on the stack (and then using it) will lead to undefined behavior. Don't do it - finding a way to silence the compiler warning does not make it safe.

英文:

The warning for this:

struct Node* createNode(void* value) {
    struct Node node = {.val = value, .next = NULL};
    return &node;
}

is because node is known to be on the stack, and the use of a pointer to that will lead to undefined behaviour.

The lack of warning for this, which is what I think you are asking about:

struct Node* createNode(void* value) {
    struct Node node = {.val = value, .next = NULL};
    struct Node* temp = &node;
    return temp;
}

is that whilst it is clear that temp points to a structure on the stack, since it is a pointer (and not the address of a variable), it could conceivably point to something else.

For the compiler to detect the same problem, it would have to implement some kind of tracking of values that are probably not worth it in general terms.

In all cases, whether you get a warning / error or not, returning the address of an automatic variable on the stack (and then using it) will lead to undefined behaviour. Don't do it - finding a way to silence the compiler warning does not make it safe.

答案3

得分: 0

这是一个非常好的警告。

当你返回一个局部变量的地址时,返回值显然是荒谬的,因为该变量已经不存在了。

当以足够低的优化级别进行编译时,编译器不会捕获你通过变量来执行此操作。(总的来说,这是一个无法解决的问题,所以在足够复杂的代码中它也不会发生。)

你应该这样做:

    struct Node* createNode(void* value) {
        struct Node *node = malloc(sizeof(struct Node));
        node->val = value;
        node->next = NULL;
        return node;
    }

这将把它放在堆上,所以它不会消失。

在使用完毕后,不要忘记在调用函数中调用 free(node)(或者在它的调用者中,等等)。

英文:

That is a really good warning.

When you return the address of a local variable, the return value is clearly nonsensical as the variable does not exist anymore.

When compiling at sufficiently low optimization level, the compiler won't catch you doing it through a variable. (In general it's an unsolvable problem so in convoluted enough code it won't anyway.)

You want

    struct Node* createNode(void* value) {
        struct Node *node = malloc(sizeof(struct node));
        node->val = value;
        node->next = NULL;
        return node;
    }

This puts it on the heap so it doesn't go away.

Don't forget to call free(node) in the calling function (or it's caller, etc.) when you're done with it.

huangapple
  • 本文由 发表于 2023年7月18日 07:15:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76708635.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定