函数里面的局部变量只是在函数里面,一旦函数执行完毕,(栈)局部变量的内存就会被释放掉(堆需要程序猿手动释放)。如果我们返回是值,那么函数会将局部变量值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"