2011-09-14 98 views
1

为什么这段代码给出了意想不到的输出。返回地址C

int * func(int *xp) 
{ 
    int y = 10 + *xp; 
    return (&y); 
} 
void main() 
{ 
    int x = 10; 
    int *xp = func(&x); 
    printf("%d\n", x); 
    printf("%d\n", *xp); 
} 

预期输出:

10 
20 

实际产出:

10 
1074194112 
+4

'无效main' ** ARRRRRRRRGGGGGGGGHHHHHHHH!** – pmg

+0

样的一个常见问题。参见[埃里克利珀的解释(http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope/6445794#6445794)。 1851 upvotes和计数... – eran

+1

@pmg最新的问题与无效主???当编译器没有给出任何错误,那么为什么你worrie? –

回答

11

你是返回一个指针变量(y),其超出范围你离开func的时刻。这是未定义的行为。

这是不完全清楚你想达到什么目的,但有几个方法来解决这个问题:

  1. 回报int的价值;
  2. 修改*xp到位,不返回任何东西;
  3. 取额外的int*参数并将结果存储在那里(再次返回void);
  4. 使用mallocnew分配堆上的内存,并返回(调用者将负责正确释放该内存)。

这是不可能说出了上述的适用于您的问题不知道的大背景下。

最后,main() should return int(谢谢@pmg发现这个)。这与您遇到的问题无关,但值得指出。

+0

我们要求对此进行变更以面试候选人。 – user47559

2

因为函数返回时y超出范围。请记住,y是在堆栈中声明的。这是一个未定义的行为。

1

返回局部变量的地址,然后解除它导致未定义的行为

由于printf调用使用与func相同的内存(堆栈)区域,因此它们会用它们自己的内部变量和函数参数覆盖func的堆栈帧。

为了解决这个问题,在malloc分配内存:

int* func (int *xp) { 
    int* res = malloc(sizeof(int)); 
    if (!res) { 
    perror('Cannot allocate memory in func'); 
    exit(1); 
    } 
    *res = 10 + *xp; 
    return res; 
} 

不要忘记free它:

int main(void) { 
    int x = 10; 
    int *xp = func(&x); 
    printf("%d\n", x); 
    printf("%d\n", *xp); 
    free(xp); 
    return 0; 
} 
+0

要便携'main'应返回'int'。我改变了你的答案。 – pmg

+0

@pmg谢谢,应该包括在首位。 – phihag

2

< real_life_example>

想象一下,你把一个苹果放在桌子上。然后你写下它在一张纸上的位置。后来,有人来吃苹果。现在纸上的位置没有意义。

</real_life_example>

+2

......并且你可以在同一个地方抓住一个香蕉,让别人放在桌子上。 – phihag

+0

他他他...我喜欢你的评论。 –

+1

将“香蕉”替换为“充满刀片的苹果”,更像是你的代码中发生了什么...... :-) –

1

func应该是这样的:

// C++ 
int* func(int* xp) 
{ 
    int* y = new int; 
    *y = 10 + *xp; 
    return y; 
} 
0

正如大家已经提到的,你试图返回一个临时变量的地址。没有人提到过最简单的解决方案。在该函数内将该变量作为静态投射。这使得它保留在整个程序的内存中。

int * func(int *xp) 
{ 
    static int y; 
    y = 10 + *xp; 
    return (&y); 
} 
void main() 
{ 
    int x = 10; 
    int *xp = func(&x); 
    printf("%d\n", x); 
    printf("%d\n", *xp); 
} 

这个按预期工作。当然,有更好的方法可以解决这个问题,但如果你确实想在函数范围内声明一个变量并返回它的地址,这是最简单的解决方案。请记住,每次调用这个函数时,它都会修改y,它不会给你一个副本。