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

标签 c pointers

这是C语言类(class)中的一个问题。有人想从带有指针的函数返回一个值。他将指针地址分配给 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;
}

最佳答案

当函数被调用时,参数(以相反的顺序)、返回地址和调用者的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

我很高兴看到这个问题的更清晰或不同的解释。

关于c - 函数调用后返回的指针值意外更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25789895/

相关文章:

c - 在 R-Pi 上用 C 语言生成随机数

c - 多进程读/写fifo

c - 无法使用 scanf() 将参数传递给函数

c - 使用 pthreads 管理链表

c - C语言中如何正确使用指针

c - 为什么我的代码不倒带并将输入保留在缓冲区中?

c - 如何将指针指向的 textf 的内容复制到 char 数组(即指针 -> char 数组)

PHP |通过重新排序从数组中删除元素?

c - 为什么 "gcc -Wall"不警告 "if (ptr < 0)"?

与 C 中的 typedef 和指针混淆