函数里面的局部变量只是在函数里面,一旦函数执行完毕,(栈)局部变量的内存就会被释放掉(堆需要程序猿手动释放)。如果我们返回是值,那么函数会将局部变量值copy并返回。如果是指针,那么函数就会直接返回指针,如果在这种情况下调用,就会出现错误,因为内存已经被释放了。下面一一来举例说明这个问题。
1. 直接值返回(RIGHT)
#includeusing 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)
#includeusing 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 charchar.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:1313cout << "return is " << a << endl;(gdb) p a$3 = 0x40095c "hello, I'am string constant"
3. 返回栈局部指针(WRONG)
#includeusing 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_localchar_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#include #include #include 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)
#includeusing 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"