今天被问了个问题,代码如下:
#include <stdio.h>
#include <stdlib.h>
int *p;
void f(int **q)
{
int s = 3;
*q = &s;
}
int main()
{
f(&p);
printf("%d", *p);
return 0;
}
看到这段代码时,我有两个想法:第一,指针是很蛋疼的,尤其这种int **p,这简直是脑细胞杀手;第二,这段代码是有问题的,因为在函数 f 中s是局部变量,所以当函数结束后s变量所在的空间已经被释放了。
但是这段程序还是可以运行的,运行结果是 3。
这个涉及到堆栈的问题,函数f有两个局部变量,参数int **p和int s。这两个局部变量是在堆栈中分配的,当f(&p)调用接收之后,全局变量p在函数f中获得的f的局部变量s的值(说得有点饶),在f调用结束之后,f的局部变量s所在的空间就被释放了(堆栈指针指向调用f之前所在的位置),s的空间被释放了,可以简单的理解成这段空间不受f管辖了,但是这个的值依然存储,还是3。所以这个程序依然可以正确运行,但是这段程序还是有问题的。
上面这段程序虽然可以正确运行,但是依然还是有问题的。记得Linus说过的,学程序最后的方法是:read the f**k source code。为什么说上面这段程序是有问题呢,看看下面这段代码吧:
#include <stdio.h>
#include <stdlib.h>
int *p;
void f(int **q)
{
int s = 3;
*q = &s;
}
int *pe;
void g(int **q)
{
int gs = 5;
*q = &gs;
}
int main()
{
f(&p);
g(&pe);
printf("%d\n", *p);
printf("%d\n", *pe);
return 0;
}
对于上这段代码,我觉得绝大部分的第一感觉是输出两个5,但实际上不是,有兴趣你可以试试运行看看
下面这段代码才是输出两个5的
#include <stdio.h>
#include <stdlib.h>
int *p;
void f(int **q)
{
int s = 3;
*q = &s;
}
int *pe;
void g(int **q)
{
int gs = 5;
*q = &gs;
}
int main()
{
int x,y;
f(&p);
g(&pe);
x=*p;
y=*pe;
printf("%d\n", x);
printf("%d\n", y);
return 0;
}
为什么是两个5呢,而不是一个3一个5呢?
因为函数f和函数g是相似的(借用数学里的相似和全等的概念),他们都输入一个参数,也都只有一个局部变量,函数里也没有调用其他函数(因此也不会有新的堆栈操作)。
上面这个函数还可以再变一下,如下函数又使输出什么呢?
int main()
{
int x,y;
f(&p);
x=*p;
g(&pe);
y=*pe;
printf("%d\n", x);
printf("%d\n", y);
return 0;
}
还是那句话,read the f**k source code。想知道的话,自己运行看看吧


