函数返回局部变量的一些问题

    函数里面的局部变量只是在函数里面,一旦函数执行完毕,(栈)局部变量的内存就会被释放掉(堆需要程序猿手动释放)。如果我们返回是值,那么函数会将局部变量值copy并返回。如果是指针,那么函数就会直接返回指针,如果在这种情况下调用,就会出现错误,因为内存已经被释放了。下面一一来举例说明这个问题。

1. 直接值返回(RIGHT)

#include<iostream>
using namespace std;
int myfoo()
{
        int a = 8;
        return a;
}
int main()
{
        int a = myfoo();
        cout << "return is " << a << endl;
}

这个写法是没有问题的,myfoo执行完之后a的内存会被释放掉,函数会拷贝a的值并返回,所以主函数的a和myfoo里面的a不是同一个地址。

(gdb) p &a
$15 = (int *) 0x7fffffffe58c
(gdb) p a
$16 = 8
(gdb) p &a
$17 = (int *) 0x7fffffffe5ac
(gdb) p a
$18 = 8

通过gbd可以看到函数体里面的a的地址和返回结果的a的地址是不一样的。

2. 直接返回字符串常量(RIGHT)

#include<iostream>
using namespace std;
char* myfoo()
{
        char* a = "hello, I'm string constant";
        return a;
}
int main()
{
        char* a = myfoo();
        cout << "return is " << a << endl;
}

在这个例子中,"hello, I'm string constant"是一个字符串常量,存在文字常量区。函数会讲字符串首地址返回,那么在主函数里面也可以直接使用。

$ g++ -g char.cpp  -o char
char.cpp: In function ‘char* myfoo()’:
char.cpp:6:12: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]

编译会报警,从字符串常量转换成char*

通过gbd来查看内存地址,可以看出二者内存地址都是0x40095c

(gdb) p a
$2 = 0x40095c "hello, I'am string constant"
main () at char.cpp:13
13cout << "return is " << a << endl;
(gdb) p a
$3 = 0x40095c "hello, I'am string constant"

3. 返回栈局部指针(WRONG)

#include<iostream>
using namespace std;
char* myfoo()
{
        char a[] = "hello, I'm char local";
        return a;
}
int main()
{
        char* a = myfoo();
        cout << "return is " << a << endl;
        return 0;
}

这个case是非法的。myfoo里面的a是一个栈局部变量,函数执行完毕,a的内存会被释放掉,如果在主函数里面直接使用会报错。

$ g++ char_local.cpp  -g -o char_local
char_local.cpp: In function ‘char* myfoo()’:
char_local.cpp:6:7: warning: address of local variable ‘a’ returned [enabled by default]

gcc编译则会报警,显示是一个局部变量,其实看到这个,我们就知道我们代码有问题。在通过gdb进一步查看。

(gdb) p &(a[0])
$2 = 0x7fffffffe570 "hello, I'm char local"
(gdb) p a
$3 = 0x7fffffffe570 "\200B\255\367\377\177"

&(a[0])就是取字符串首字符的地址,可以看到在myfoo里面是有值的,但是在main函数里面,可以看到内存已经被释放了。变成空了。

4. 返回堆局部指针(RIGHT)

#include<iostream>
#include<unistd.h>
#include<cstring>
#include<cstdlib>
using namespace std;
char* myfoo()
{
        char *a = (char*)malloc(100);
        strncpy(a, "hello, I am malloc", 100);
        return a;
}
int main()
{
        char* a = myfoo();
        cout << "return is " << a << endl;
        return 0;
}

通过malloc申请的变量在堆区,需要程序员自己释放(也是内存泄露的原因之一),myfoo执行完了,内存没有被释放,所以这样使用不会有问题。

(gdb) p a
$1 = 0x602010 "hello, I am malloc"
(gdb) p a
$2 = 0x602010 "hello, I am malloc"

可以看到myfoo和main里面的地址都是一样的。

5. 返回静态变量(RIGHT)

#include<iostream>
using namespace std;
char* myfoo()
{
        static char a[] = "hello, I'm static";
        return a;
}
int main()
{
        char* a = myfoo();
        cout << "return is " << a << endl;
        return 0;
}

static变量作用域是全局,所以肯定没问题。直接gdb查看可以验证。

(gdb) p &(a[0])
$2 = 0x601050 "hello, I'm static"
(gdb) p a
$3 = 0x601050 "hello, I'm static"


转载于:https://my.oschina.net/jungleliu0923/blog/194208

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值