C++ 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;
}

写在后面

臭猴子,你说这山岭外的世界,究竟是什么样的
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值