C++ char* 指向的内存区域详解
- 写在前面
- c++内存结构简介
- 指针常量和常量指针简介
- 情况一:char* 指向栈区内容
- 情况二:char* 指向堆区内容
- 情况三:char* 指向常量区内容
- 情况四:char* 指向静态区内容
- 情况五:char* 指向全局区内容
- 测试代码
- 写在后面
写在前面
之前调用别人的API,这个API返回一个const char*,当时就在想要不要自己copy一下这个值,因为不知道这个const char什么时候会被释放。于是自己下来探索了一下一个函数返回char时,char*可能指向的内存区域。
c++内存结构简介
C++ 内存主要分为栈区、堆区、全局区、静态区、常量区、代码区。
栈区:主要存放函数的形参、局部遍历
堆区:存放new出来的对象
全局区:存放全局变量
静态区:存放静态变量
常量区:存放常量(不包含局部常量)
我们知道字符串常量,例如"1234"、"abcd"这些值是存放在常量区的。
指针常量和常量指针简介
指针常量,例如const char * a,const修饰的是*,因此a指向的内容是不可以改的,也就是用a修改值是不可以的。而a本身是可以修改的,a可以指向其他地址。
常量指针,例如char * const a,const修饰的是a,因此a本身是是不可以改的,a不可以指向其他地址。而a是可以修改的,也就是用*a修改值是可以的。
注意const char * a,只是代表a指向的内容是不可以改,不代表a一定指向的是常量,a也可以指向变量,只是无法修改这个变量的值,例如下面的语法都是合法的
char a[] = "123";
const char* p = a;//p指向变量
const char* p1 = "123";//p指向常量
情况一:char* 指向栈区内容
以下3种赋值方法在函数中定义时,a都是指向栈区。
编译器会把"123"从常量区复制一个副本出来然后赋值给char a[]
char a[] = "123";//指向栈区
char a[4];//指向栈区
a[0] = '1';
a[1] = '2';
a[2] = '3';
a[3] = '\0';
const char a[] = "123";//指向栈区,不能用 a[0] = '1'; 因为是const
那 char* a = "123"
呢?其实这种赋值方法是错误的,因为"123"的类型是常量const char *,无法讲常量赋值给变量的。
情况二:char* 指向堆区内容
用new 的方法,这时a指向的是堆区的1、2、3
char* a = new char[4];//指向堆区
a[0] = '1';
a[1] = '2';
a[2] = '3';
a[3] = '\0';
情况三:char* 指向常量区内容
指向常量区,“123”就存放在常量区,因此a此时指向的是常量区
const char* a = "123";//指向常量区,不能用 a[0] = '1'; 因为是const
那 char* a = "123"
呢?其实这种赋值方法是错误的,因为"123"的类型是常量const char *,无法讲常量赋值给变量的。
情况四:char* 指向静态区内容
static char a[] = "123";//指向静态区
static const char a[] = "123";//指向静态区
同样也无法static char* a = "123"
,原因和情况三一样,a是静态变量而"123"是常量,出发用 static const char* a = "123";
情况五:char* 指向全局区内容
讲变量定义在类外时,a2指向的就是全局区
char a2[] = "123"; //全局区
const char a1[] = "123"; //全局区
需要注意的是const char* a1 = "123";
即便在类外定义,同样a1*指向的是常量区。
测试代码
用6个函数测试一下,可以看到指向栈区的指针都因为函数的出栈而被释放了。
char* Func1() {
char a[] = "123";//指向栈区
return a;
}
char* Func2() {
char a[4];//指向栈区
a[0] = '1';
a[1] = '2';
a[2] = '3';
a[3] = '\0';
return a;
}
const char* Func3() {
const char a[] = "123";//指向栈区
// 不能用 a[0] = '1'; 因为是const
return a;
}
char* Func4() {
char* a = new char[4];//指向堆区
a[0] = '1';
a[1] = '2';
a[2] = '3';
a[3] = '\0';
return a;
}
const char* Func5() {
const char* a = "123";//指向常量区
// 不能用 a[0] = '1'; 因为是const
return a;
}
char* Func6() {
static char a[] = "123";//指向静态区
return a;
}
const char* a1 = "123"; //指向全局区
const char a2[] = "123"; //指向全局区
const char* a3 = "123"; //指向常量区
int main(int argc, char const* argv[]) {
char* p1 = Func1();
const char* p11 = Func1();
char* p2 = Func2();
const char* p3 = Func3();
const char* p4 = Func4();
const char* p5 = Func5();
const char* p6 = Func6();
cout << p1 << std::endl; // 烫烫烫烫烫烫烫烫烫烫
cout << p11 << std::endl;// 烫烫烫烫烫烫烫烫烫烫
cout << p2 << std::endl;// 烫烫烫烫烫烫烫烫烫烫
cout << p3 << std::endl;// 烫烫烫烫烫烫烫烫烫烫
cout << p4 << std::endl;// 123
cout << p5 << std::endl;// 123
cout << p6 << std::endl;// 123
cout << a1 << std::endl;// 123
cout << a2 << std::endl;// 123
delete[] p4;
}
写在后面
臭猴子,你说这山岭外的世界,究竟是什么样的