C语言的那些坑(函数返回局部变量)

来源:互联网 发布:如何免费申请邮箱域名 编辑:程序博客网 时间:2024/05/21 15:19

第二个坑 函数返回局部变量问题

函数是可以返回局部变量的,比如看下面代码就是对的

int fun(){    int a = 9;    return a;}int main (){    printf("%d", fun());    return 0;}

程序的运行过程是依照栈的规则,函数开始调用就是压栈,函数调用结束就是弹栈。函数弹栈之后该函数占用的内存自然就被释放掉了(重点是……栈)。我们返回的局部变量实际上已经不是局部变量本身了,而是它的复制品。系统会创建一个临时变量来拷贝被return的变量的值。
因此上面的代码是正确的。那么我们来看下面的代码

char* fun(){    char a[128];    sprintf(a, "c语言的那些坑");    return a;}int main (){    printf("%s", fun());    return 0;}

这段代码就是错误的,假设程序照常运行,会出现什么情况。函数fun()返回了a之后,会将a的值拷贝到临时变量。注意是将a的值拷贝到临时变量,而不是拷贝a指向的那块内存里的值。a是什么,a是局部变量数组a的首地址。而a所指的值他的生命周期在函数fun运行结束时就已经停止。内存被销毁。主调函数得到的指针指向的区域已经被销毁,因此是错误的。
继续看下面这段代码

char* fun(){    char *a;    a = "c语言的那些坑";    return a;}int main (){    printf("%s", fun());    return 0;}

还按照刚才的逻辑分析,主调函数可以得到a的值,a的值是什么,a的值是“C语言的那些坑”这个字符串所在的地址。我们强调过,函数调用结束后,函数的栈内存都会被释放掉。注意我说的是栈。而“C语言的那些坑”这个字符串没有存放在栈内。因此,被调函数结束调用时,不会释放掉这个字符串所在的内存。所以主调函数拿到了指针之后,可以得到指针指向的内存的内容。

大概总结一下,函数返回局部变量是被允许的。只是在返回指针变量的时候,我们需注意,在程序跳出这个函数后这个指针所指的内容是否依旧存在。判断指针所指内容是否依旧存在,这就要求我们对程序运行过程中内存的分配规则有一定的了解。具体内容可以百度一下“内存四区模型”。我们这里只告诉大家我们容易犯的错误。
看下面代码

char* fun_1(){    char *a = "c语言的那些坑";    return a;}char* fun_2(){    char a[] = "c语言的那些坑";    return a;}

这两个函数看似类似,使用方法也类似,但本质不同,所以结果不同。fun_1是创建一个指针,指针指向了常量区的字符串。函数调用结束后,主调函数得到指针值,依旧可以访问指向的内存。fun_2 是创建了一个数组,数组的内容是那个字符串。这个数组是在栈上存储的,当函数调用结束后,栈内存被回收。所以主调函数得到的指针指向了一个已经被回收的地方,因此fun_2是错误的。