今天和同学讨论了函数返回局部变量,这里有许多的细节,在这里做一下总结
函数返回局部变量一定要注意,要区分两点:
1、分清楚返回的是局部变量的值还是地址;
2、分清楚返回的是否是栈区
如果返回的是值就可以,不涉及地址就不会出错;如果返回的是全局区/堆区的变量,无论是返回值、地址都可以
局部变量作用域只在函数内部,在函数返回后内存被释放。只是把指针复制后返回了,但是指针指向的内容已经被释放了,这样指针指向的内容就是不可预料的内容,调用就会出错
总之---时刻牢记返回的是值还是地址,如果是地址,不能返回栈区的变量的地址
例子如下:
首先内存广义分为全局区、代码区、堆区、栈区(其实还可以分的很细,后面还会再总结,在这里都是为了更好理解返回局部变量)
#include <stdio.h>
//1、返回的值是字符串常量的首地址,但“hello”是一个字符串常量,存放在只读数据段(全局区),在re1函数返回后内存不会被释放(整个程序运行结束才会释放),故不会出错
char *re1()
{
char *p="hello";
return p;
}
//2、返回的是字符数组(数组中存放字符串)的首地址,其返回的是地址并且存放在栈区,在re2函数返回后栈区内存释放,内存地址已经释放,所以地址中存放的内容未知,不可行
char *re2()
{
char p[]="hello";
return p;
}
//3、返回的是字符数组(数组中存放字符串)的首地址,但其被声明为static类型,其返回的地址存放在全局区,可行
char *re3()
{
static char p[]="hello";
return p;
}
//4、f1返回一个局部变量的值,无论这个值在哪个区都不会出错;f2返回地址,并且返回的是存放在栈区的变量地址,不可行(可以加static,可行)
int f1()
{
int a;
a = 10;
return a; //允许
}
int * f2()
{
int a;
a = 10;
return &a; //无意义,不应该这样做
}
//5、C++返回类型是int &, f3返回一个局部变量的引用(a的副本),需要说明的是在接收引用时,有两种接受方法:(现在粗暴的理解为用int接收就是值,用int&接收就是地址)
// 1、int d1 = f3;//返回一个a的副本10,用d1接收,不涉及地址,可行
// 2、int &d2 = f3;(内部会*d2)相当于返回一个内存空间,然后给内存空间起了一个别名d2,d2和f3指向同一片地址空间,但是这片地址空间已经被释放了,不可行
int & f3()
{
int a;
a = 10;
return a;
}
//6、返回指向堆内存的指针是可以的,因为堆区地址只要不手动释放就一直存在
char *re4(int num)
{
char *p = (char *)malloc(sizeof(char) * num);
return p;
}
int main()
{
char *a; //字符串常量在c中这样接收,但在C++中使用const char * a接收
a = re1();
char *b; //字符数组c和C++都是这么接收的
b = re2();
char *c;
c = re3();
//f3的两种接受方法
int d1 = f3;
int &d2 = f3;
return 0;
}