下面的程序在第二行输出乱码:
#include <iostream>
using namespace std;
char * fun()
{
char p[] = "ABC";
return p;
}
void main()
{
char *s;
s = fun();
cout << "Yang" << endl; //运行到此行停住,看看s的值是什么?"ABC"!
cout << s << endl; //乱码了
}
若将 p[] 改为 *p 结果就正常了,这是为什么?
问老师的结果是 p[] 是在栈上分配,而 *p 是在堆上分配,可我并没有malloc或new啊?
问题一:
楼主似乎还没搞清楚存储类的一些细节。
char p[]是auto的,程序离开fun()后p[]就消失了,它本来的存储区域的内容是不确定的,所以s会出现乱码;而"ABC"是static的,此时s实际上是一个指向字符串常量的指针(只不过“ABC”仍然不能被其它函数直接链接),离开fen()后“ABC”仍存在,因此s能正确表示“ABC”的内容。
问题二:
虽然char p[]和char *p同是局部变量,但对于char p[]来说,p是一个auto变量的地址,而非指向"ABC"(字符串常量)的地址,就是说,系统会为p[]分配不同于“ABC”所处区域的另一块内存,然后把“ABC”的内容复制过去,fen()结束后,p[]的内容不再确定,这会产生问题,会使s返回一个不确定的内容,因此系统会警告returning address of local variable or temporary
。而对于char *p="ABC",系统把"ABC”的地址传给指针p,p的地址就是“ABC”字符串常量的地址,这个常量是static的,fen()结束后它仍存在,s指向的内容是确定的,因此系统不会给予警告。
//char p[]="abc"定义的p数组能再赋值,而char *p="abc"是指针p指向常量数组,不能对p再赋值了
在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
char a[] = "a"; //数据保存在堆
char *b = "b"; //"b"保存在常量区,b保存在堆
int main()
{
char c[] = "c"; //数据保存在栈上
char *d = "d"; //"d"保存在常量区,d保存在栈上
}
常量存储区是一块比较特殊的存储区,他们里面存放的是常量,不允许修改。所以不能b[0],d[0]进行修改。将它们的地址输出:
printf("0x%08x 0x%08x\n", &a, &(*a));
printf("0x%08x 0x%08x\n", &b, &(*b));
printf("0x%08x 0x%08x\n", &c, &(*c));
printf("0x%08x 0x%08x\n", &d, &(*d));
在我的电脑上是:
0x08049774 0x08049774
0x08049778 0x080485f5
0xbfd917a9 0xbfd917a9
0xbfd917a4 0x080485e0
可以看到a,c是数组(&a==&(*a),&c==&(*c)),但b,d是指针,它们指向的区域基本是连续的(在常量区上),同时&a与&b,&c与&d的地址也是基本连续的。另外可以看到,对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。