详解C语言中return返回函数局部变量的问题

编辑: admin 分类: c#语言 发布时间: 2021-12-12 来源:互联网
目录
  • return返回栈区局部变量的指针
  • return返回栈区局部的临时变量
  • return只读数据段和static数据

在计算机中,释放空间并不需要将空间中的内容全部置成0或者1,而是只要设置这一块空间的数据无效即可。比如在下载文件时需要花很长时间,但是删除文件却只要几秒钟,这是因为操作系统只是把文件标识(文件头链接)删掉了,文件原文还保留着,我们没了文件标识就找不到这个文件了。所以删除后的文件,还可以用特殊的办法被找回来。

这也就意味着,当函数结束调用的时候,函数中的局部变量实际上还是在的,只是函数原来的空间还给编译器(释放)了,也就是说函数中的局部变量是可以被编译器修改的。
虽然函数结束后空间还给了编译器,但是我们依然可以通过指针找到对应的局部变量的空间。

return返回栈区局部变量的指针

通过上面的分析,如果我们返回局部变量的指针,是不是可以直接找到这个局部变量呢?

返回了一个局部变量的指针,而恰好局部变量偏偏又在函数结束后销毁,但指针并没有被销毁,而是被返回,那也就是说,指针指向的正是一个被销毁了的对象。

比如下面的代码:

#include <stdio.h>
char* returnStr()
{
    char p[] = "hello world!";
    return p;
}
int main()
{
    char* str;
    str = returnStr();
    printf("%s\n", str);
    return 0;
}

在这里插入图片描述

可以看到原来p的空间已经被修改了,但是很奇怪,是谁进行的修改呢?

通过调试可以发现,当函数结束后,运行printf打印之前,str指向的空间中的字符串是在的:

在这里插入图片描述

但是一运行printf打印操作,str指向的空间中的字符串就会被修改:

在这里插入图片描述

这其实很好解释,因为printf本身也是一个函数,函数都是在栈区开辟的,而函数开辟的空间叫做栈帧,函数结束栈帧就还给了编译器:

在这里插入图片描述

了解了这些,那是不是只要我们多建立几个函数栈帧,是不是就可以使returnStr的函数栈帧不被覆盖了?答案是肯定的:

#include <stdio.h>
char* fun6()
{
    char p[] = "hello world";
    return p;
}
char* fun5()
{
    return fun6();
}
char* fun4()
{
    return fun5();
}
char* fun3()
{
    return fun4();
}
char* fun2()
{
    return fun3();
}
char* fun1()
{
    return fun2();
}
char* fun()
{
    return fun1();
}
int main()
{
    char* str;
    str = fun();
    printf("%s\n", str);
    return 0;
}

在这里插入图片描述

在这里插入图片描述

不过随着函数栈帧的逐渐增多,原来的fun6函数空间迟早也会被覆盖。

在函数体内定义的局部变量是有临时性的,当局部变量释放后随时都有可能会被修改,所以我们不能通过指针使用已经被释放的局部变量。

return返回栈区局部的临时变量

如果我们不返回指针,而是返回局部变量会怎么样呢?
按理来说局部变量也会被修改。

#include<stdio.h>
int test()
{
	int a = 10;
	return a;
}
int main()
{
	int b = test();
	printf("%d", b);
}

在这里插入图片描述

通过反汇编可以看到,局部变量a的值10通过寄存器交给了调用的b,所以即使局部变量a空间的10已经被修改,也不会影响b的内容:

在这里插入图片描述

return只读数据段和static数据

如果返回只读字符串则不会被覆盖,因为数据不是在栈区,而是在静态区:

在这里插入图片描述

同理如果将字符串用static修饰也是如此:

在这里插入图片描述

另外,返回堆内的指针也是可以的。

到此这篇关于详解C语言中return返回函数局部变量的问题的文章就介绍到这了,更多相关C语言return返回函数局部变量内容请搜索海外IDC网以前的文章或继续浏览下面的相关文章希望大家以后多多支持海外IDC网!

【本文由:香港大带宽服务器提供】