美文网首页iOS Developer
函数中返回局部变量

函数中返回局部变量

作者: 寒咯 | 来源:发表于2017-08-11 10:53 被阅读90次

我们都知道,函数的局部变量只能在声明它的函数中访问,超出作用域后的非法访问会得到不可预测的值,甚至导致程序崩溃。

这么说来返回值岂不是都要用全局变量?既然都使用了全局变量,那还有返回的必要吗?那么函数的返回值岂不是没有存在的意义了?

上一篇中,我们了解了函数调用栈,趁热打铁,这次我们就刚好利用学到的知识来解决眼前的问题。

测试用例

char* get_memory() {
    char p[] = "hello world";
    return p;
}

int main(int argc, const char * argv[]) {
    char* str = NULL;
    str = get_memory();
    printf("%s",str);
    return 0;
}

问题1. char p[] 真的是出了函数范围就访问不到正确内容了吗?

进入反汇编调试界面,断点在 get_memory 函数调用前:

2017-08-07-memory2-0.png
a. -18(%rbp) 是局部变量 char* str,用来存放 get_memory 函数的返回值;
b. -18(%rbp) 的值在 printf 函数调用时,作为第二个参数;

进入 get_memory 函数:

2017-08-07-memory2-1.png
c. get_memory 函数返回指针指向栈中内存地址 0x00007fff5fbff69c(-0x14(%rbp));
d. 第 9 到 12 行指令是将 "hello world" 这个字符串中的每个字符拷贝到 0x00007fff5fbff69c(-0x14(%rbp) 开始的连续地址中;

调用 printf 函数之前:

2017-08-07-memory2-5.png

可以看到,虽然已经结束了 get_memory 函数的调用,但是栈中分配给局部变量 char p[] 的内存地址,并没有被释放或者覆盖,此刻依然还是可以访问到正确的内容;

但是在函数调用栈里,我们说过,栈是由编译器自动分配和释放,是不可控的,这里只是为了理解过程。

2017-08-07-memory2-3.png

问题2. str 为什么不能被 printf 正确打印?

2017-08-07-memory2-4.png

通过 问题1. 我们分析得知,get_memory 中的局部变量 char p[] 在未调用 printf 函数之前,是可以正确访问的。

那么无法正确打印的问题,很明显就出在 printf 函数本身。

调试框输入 b printf 命令,可以在 printf 函数内部打上断点。

2017-08-07-memory2-6.png

printf 在更新了 rbp 之后,直接 push 了三个空内容寄存器,将 get_memory 函数中分配给 char p[] 的内存覆盖。

通过简单的栈图,更直观的感受一下:

2017-08-07-memory2-7.png

此刻的内存情况:

2017-08-07-memory2-8.png

如何正确返回局部变量?

我们在分析 问题1. 的时候,从 get_memory 函数的反汇编代码可以清楚的看到,局部变量 char p[] 实际上是在栈上分配了一段连续内存,再将 "hello world" 中的字符拷贝到其中,然后返回首地址;而栈是由编译器自动分配和释放的,是不可控的,那么返回的地址中的内容,当然也就是不可控的,这显然不是我们的初衷,所以 函数不能返回指向栈内存的指针

正确的返回姿势:

  • 声明为 static 后,变量将存储在静态存储区,分配一次后不会销毁,直到程序结束都有效,不再受函数作用域限制。
  • malloc 在堆上分配内存,返回指向堆内存的指针,需要手动释放内存,防止内存泄漏。
  • char *p = "hello world" 字符串分配在常量区,返回指向常量区的指针。

对于基本数据类型,编译器会直接进行值拷贝。

相关文章

  • 函数中返回局部变量

    我们都知道,函数的局部变量只能在声明它的函数中访问,超出作用域后的非法访问会得到不可预测的值,甚至导致程序崩溃。 ...

  • Python语言基础(五)

    函数的返回值 返回值可以是任何数据类型,使用return语句可以返回函数值并退出函数 全局变量和局部变量 在函数中...

  • JavaScript闭包

    闭包就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。 闭包就是就是函数的“堆栈”在函数返回后并不释...

  • iOS面试杂记

    1. 函数局部变量的return R:一般的来说,函数是可以返回局部变量的。 局部变量的作用域只在函数内部,在函数...

  • 函数式编程

    高阶函数 返回函数 函数作为返回值 闭包 注意到返回的函数在其定义内部引用了局部变量args,所以,当一个函数返回...

  • 2018-11-27

    函数的变量 局部变量:函数中定义的变量 全局变量:代码顶部定义的变量 函数的返回值 函数被调用后会返回一个指定的值...

  • iOS面试杂记

    1. 函数局部变量的return R:一般的来说,函数是可以返回局部变量的。 局部变量的作用域只在函数内部,在函...

  • 2018-08-23

    闭包: 注意到返回的函数在其定义内部引用了局部变量args,所以,当一个函数返回了一个函数后,其内部的局部变量还被...

  • 字符串(一)

    字符串作为函数的返回值 函数中声明的字符数组是局部变量 我们编译程序发现警告,如下图 警告告诉我们函数返回的是局部...

  • Python 闭包

    Python v3.7.0 在函数嵌套的程序结构中,如果内层函数包含对外层函数局部变量的引用,同时外层函数的返回结...

网友评论

    本文标题:函数中返回局部变量

    本文链接:https://www.haomeiwen.com/subject/mkjlrxtx.html