关于堆栈和指针

本文通过几个示例探讨了C语言中指针指向局部变量可能导致的问题,并解释了不同情况下程序行为的变化。

今天被问了个问题,代码如下:

#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。想知道的话,自己运行看看吧大笑大笑大笑




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值