函数调用后,返回的指针值意外更改

时间:2014-09-11 14:19:29

标签: c pointers

这是C语言课程的问题。有人想从带有指针的函数返回一个值。他将指针地址分配给result_ptr并打印该指针的值。

当没有A行时,printf()工作正常:printf()打印3.

但是,当在printf()前面调用另一个addition()函数时,会发生错误:printf()打印5。

如果线A被注释掉,线B,另一个printf()函数被取消注释:printf()打印0。

到底发生了什么?

int *addition(int a, int b) {
    int d = a + b;
    int *c = &d;
    return c;
}

int main(int argc, const char * argv[])
{
    int *result_ptr = addition(1, 2);
    addition(2, 3); // Line A
//      printf("Another line\n"); // Line B
    printf("result = %d \n", *result_ptr);
    return 0;
}

1 个答案:

答案 0 :(得分:2)

当调用函数时,参数(以相反的顺序),返回地址和调用者的EBP(存储函数在执行后返回的位置)被压入堆栈。被调用者设置一个堆栈帧,存储其局部变量并保存3个寄存器的内容,如果它们被修改,则保存EBX,ESI和EDI。当函数完成执行时,框架会弹出,堆栈的顶部返回到调用被调用者之前的高度。

在此示例中,int * c声明一个本地指针变量,该变量存储在被调用者帧内的堆栈中。返回该指针返回堆栈帧上的地址。由于连续的addition()调用会导致相同的堆栈空间分配,因此相同地址的内容将被写入两次。这就是为什么第二个函数调用将写入5,从第一个函数调用覆盖3:它们正在修改同一内存位置的值。但是,当调用printf()时,堆栈空间用于完全不同的堆栈帧。然后,同一位置存储未定义的值。

为了避免这种情况,最好将指针返回到堆上的位置而不是堆栈上。注意在内存分配后释放指针以避免泄漏。

int *addition(int a, int b) {
    int *c = (int *) malloc(sizeof(int));
    *c = a + b;
    return c;
}

// in main
int *result_ptr=addition(1,2);
printf("value = %d \n",result_ptr);
free(result_ptr);
result_ptr=0;

参考:http://www.csee.umbc.edu/~chang/cs313.s02/stack.shtml

我很高兴看到这个问题有更明确或不同的解释。