为什么字符串常量赋值给指针和数组后,指针不可以修改字符串,而数组可以

问题描述

int main() {
	char* p;
	p = "hello";
	p[2] = 'A'; // 非法操作
	char c[30] = "hello";
	c[2] = 'A'; // 正确操作
}

结论:
数组c的声明,是将字符串常量“复制”到数组中,复制来的字符串是可以修改的
指针p的声明,指向的是字符串常量的地址,而常量只读不可修改

分析过程:
先看这段代码

	char* p, *m;
	p = (char*)malloc(30);
	m = (char*)malloc(30);
	p = "hello";
	char* q="hello";
	char c[30] = "hello";
	p[2] = 'A';
	puts(p);
	

解释:为什么要给p动态申请内存,因为要与q对比,有人认为是因为指针没有动态申请内存,而真实的结果是申请内存后,p的值又被字符串的地址覆盖了。

首先要知道,数据存储会放在堆内存和栈内存,此外,还有一个数据区,这里叫做字符串常量区,我们会把"hello"存储在字符串常量区。
先看这张图
在这里插入图片描述
要看每个变量的存储地址:
数组c的存储地址为 0x004FFD1C
指针p的存储地址为 0x004FFD5C
指针q的存储地址为 0x004FFD44
你会发现他们地址几乎都在一起,因为他们存储的地方是栈内存

要知道p = "hello";意思是将字符串"hello"的地址存储到p内
而p内存储字符串的地址为 0x00667B30
q内存储的字符串的地址为 0x00667B30
你会发现存储的地址是一样的,说明字符串"hello的地址放在一个地方,也就是我们说的字符串常量区,字符串常量区内的元素,只读不可修改

你们会问,为什么p内的地址为字符串常量的地址呢?
首先,指针p申请动态内存后,p内存储的是申请的内存的起始地址,而之后,p又存储字符串“hello”的地址,所以,最后p内存储的地址为字符串常量“hello”的地址。

你们又会问,为什么数组可以修改呢?
首先看这两张图的对比
在这里插入图片描述
在这里插入图片描述

经过对比,我们可以知道,数组c内存储的是字符串,
数组在被字符串赋值时,是将字符串常量的值“复制”到数组中,通俗的理解是

char c[30] = "hello"; // 等价于 strcpy(c, "hello");

大家可以看一下这个代码:

int main() {
	char* p, *m;
	p = (char*)malloc(30);
	m = (char*)malloc(30);
	//p = "hello";
	strcpy(p, "hello");
	char* q="hello";
	char c[30] = "hello";
	p[2] = 'A';
	puts(p);
}

这里输出结果为:
在这里插入图片描述
大家又会问:为什么用strcpy(p, "hello");
因为字符串被复制到堆内存中,而不是访问字符串常量区
指针p首先动态申请内存,这时,指针p的值是申请的内存起始地址,所以strcpy是将字符串复制到申请的内存当中。
所以strcpy是可以修改的

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不知名小白猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值