C++中内存布局,内存地址:栈区>堆区>静态存储区
一、字符串常量和字符串变量
我们知道字符串常量是存储在文字常量区,也即C++中的静态存储区。
而字符串变量一般定义在栈区,当使用malloc时则定义在堆区。
char* ss = "hello world";
printf("%p\n", &ss); //字符串变量ss的存储地址(变量声明的地址)
printf("%c: %p\n", ss[0], &(ss[0]));//字符串变量ss中第一个字符h的存储地址
printf("%c: %p\n", ss[1], &(ss[1]));//字符串变量ss中第二个字符e的存储地址
printf("%p\n", &"hello world");//字符串常量的首地址
printf("%p\n", &("hello world"[0]));//字符串常量第一个字符h的存储地址
printf("%p\n", &("hello world"[1]));//字符串常量第二个字符e的存储地址
/*
0x7fffecff31b8 栈区
h: 0x401420 静态存储区
e: 0x401421 静态存储区
0x401420 静态存储区
0x401420 静态存储区
0x401421 静态存储区
*/
/*用malloc申请内存*/
char* ss = (char*)malloc(128);
memset(ss, 0, 128);
strcpy(ss, "hello world");
printf("%p\n", &ss); //字符串变量ss的存储地址(变量声明的地址)
printf("%c: %p\n", ss[0], &(ss[0]));//字符串变量ss中第一个字符h的存储地址
printf("%c: %p\n", ss[1], &(ss[1]));//字符串变量ss中第二个字符e的存储地址
printf("%p\n", &"hello world");//字符串常量的首地址
printf("%p\n", &("hello world"[0]));//字符串常量第一个字符h的存储地址
printf("%p\n", &("hello world"[1]));//字符串常量第二个字符e的存储地址
/*
0x7ffc38cae008 栈区
h: 0x628130 堆区
e: 0x628131 堆区
0x401470 静态存储区
0x401470 静态存储区
0x401471 静态存储区
*/
- 字符串变量存储在静态存储区;
- 在栈区声明一个字符串变量,char* ss = "hello world";这句代码会将栈区变量ss指向静态存储区的字符串,因此访问栈区ss变量时,是访问了静态存储区的"hello world"。
- 在栈区声明一个字符串变量,char* ss = (char*)malloc(128);这行代码在堆区申请了一块128字节的内存,并将栈区变量ss指向这块堆内存,strcpy(ss, "hello world");则将静态存储区的字符串拷贝至堆区。
其他需要注意的点:
我们在栈区char* ss时,只是在栈区声明了一个字符串变量,如果想使用strcpy拷贝字符串,则目的地址必须是申请的堆空间字符串变量地址,或者是栈空间的字符数组。
// char* ss;
// strcpy(ss, "hello world");//错误,不能讲常量字符串拷贝至一个字符串变量,因为该字符串变量没有申请空间存储
char ss[128];
memset(ss, 0, 128);
strcpy(ss, "hello world");//正确,ss是栈空间的字符数组
二、string变量
string是C++定义的类,在其实现中,数据内容存储在堆空间中,在对象析构时将会释放其申请的堆内存,还要注意的是使用string的“+”运算符等时,拼接到一起的字符串其地址空间可能是不连续的。
string tmpstr = "hello world";
printf("tmpstr: %p\n", &tmpstr);//string变量tmpstr的存储位置
printf("%c %p\n", tmpstr[0], &(tmpstr[0]));//tmpstr变量中字符串第一个字符h存储的位置
printf("%c %p\n", tmpstr[1], &(tmpstr[1]));//tmpstr变量中字符串第二个字符e存储的位置
printf("%c %p\n", tmpstr[10], &(tmpstr[10]));//tmpstr变量中字符串第11个字符d存储的位置
tmpstr += "123";//拼接一段字符串
printf("%c %p\n", tmpstr[11], &(tmpstr[11]));//拼接后的tmpstr第12个字符1存储的位置
printf("%c %p\n", tmpstr[12], &(tmpstr[12]));//拼接后的tmpstr第13个字符2存储的位置
printf("%p\n", &"hello world");//"hello world"字符串首地址
printf("%p\n", "hello world");
/*
tmpstr: 0x7ffe73dbd690 栈区
h 0x9bf028 堆区
e 0x9bf029
d 0x9bf032
1 0x9bf063
2 0x9bf064
0x400d20 静态存储区
0x400d20
*/