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

  • Post author:
  • Post category:其他



问题描述

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是可以修改的



版权声明:本文为weixin_45695001原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。