2017-07-15 61 views
1

有人请向我解释为什么输出下面的代码是6而不是5?我不明白如何调用hoo改变m-> x的值。即使在运行代码并遵循其每一步之后,仍然不清楚。结构和指针。输出不清楚

#include <stdio.h> 
#include <stdlib.h> 

typedef struct a { 
    int x; 
    struct a* next; 
}a_t; 

a_t* foo() { 
    a_t* varp, var = { 5,NULL }; 
    varp = &var; 
    return varp; 
} 

a_t* hoo() { 
    a_t* varp, var = { 6,NULL }; 
    varp = &var; 
    return varp; 
} 

void main() 
{ 
    a_t* m = foo(); 
    hoo(); 
    printf("%d", m->x); 
} 
+1

你的代码是未定义的行为。 – tilz0R

+1

'var.x'在'foo'之外无效。 – BLUEPIXY

+1

因为你不能从一个函数返回一个局部变量。您的指针指向您尝试访问时已释放的数据。 SO上有很多重复的内容。 –

回答

2

你的功能hoofoo正在返回指向局部变量是定义*不确定behavior`。

它们都执行不同的结构(2个副本),并且您从第一个打印值。

由于您首次在函数foo上创建了堆栈结构,因此您有幸在功能hoo的函数中同时创建了堆栈上的函数。

因此你有覆盖。

如果要从函数返回指针,请使用static或使用malloc在堆上动态分配内存。

a_t* foo() { 
    a_t* varp = malloc(sizeof(*varp)); 
    varp->m = 5; 
    return varp; 
} 

void main() 
{ 
    a_t* m = foo(); 
    hoo(); 
    printf("%d", m->x); 
    free(m); 
} 

现在你在堆栈外分配内存,它将按照你的预期工作。

+0

谢谢你的明确答案。代码错误的目的是它是我发现练习的一部分。我只是没有任何解释的输出,并想知道在内存中发生了什么。 – roy360

+0

返回指向本地变量的指针本身不会导致未定义的行为。调用者解除引用这些指针的任何尝试都会发生。 – Peter

+0

@彼得是的,我同意你的看法。 – tilz0R

2

您的代码有未定义的行为。让我们看看为什么。

a_t* foo() { 
    // creates a variable on the stack 
    a_t* varp, var = { 5,NULL }; 
    // sets address of variable on stack to another variable on the stack 
    varp = &var; 
    // you return that address on the stack 
    return varp; 
} 

a_t* hoo() { 
    // creates a variable on the stack 
    a_t* varp, var = { 6,NULL }; 
    // sets address of variable on stack to another variable on the stack 
    varp = &var; 
    // you return that address on the stack 
    return varp; 
} 

为什么以上代码为undefined behavior?在函数调用hoofoo结束后,您将返回您不再拥有的变量(包含地址)。 系统现在拥有该内存! 电脑很愚蠢,会盲目地执行你给他们的任何命令。我想你打算使用malloc来保存你想要在函数调用堆外保存的变量。

a_t* foo() { 
    a_t *varp = malloc(sizeof(struct a_t)); 
    varp->x = 5; 
    varp->next = NULL; 
    return varp; 
} 

你能修复另一个吗?

+0

非常感谢,非常清楚的解释。 – roy360

2

基本上,当你调用hoo()时,你创建了一个与使用foo之前创建的var和var不同的var和var,并将它存储在变量m中。然而,这个新的varp被创建在与var的var相同的内存地址上并且覆盖了它的值。

如果您使用F5逐行执行并在main行中添加3个断点,请在变量m上添加一个监视,然后进入hoo(),并注意分配给varp的内存地址与m ...因此,当你离开hoo()并返回到main时,将丢失以m为单位存储的值,因为它已被覆盖。notice the cursor is still at line 22 and didn't overwrite yet

+0

谢谢!我从中学到了很多 – roy360

0

您可以定义“static var ...”。 因此var在函数返回后仍然存在。