C语言中char *与char[]的区别及字符串处理相关疑问
1. 数组名与首元素地址相同的本质
首先明确:C语言的数组不是指针,你观察到的地址值相同只是内存布局的巧合,二者类型完全不同:
&name的类型是char (*)[10],即指向长度为10的char数组的指针,代表整个数组的起始地址&name[0]的类型是char *,代表数组第一个元素的起始地址
整个数组的存储起始位置和首元素的存储起始位置天然重合,所以打印出来的地址数值相同。你可以通过指针运算验证差异:&name + 1会向后偏移10字节(步长为整个数组的长度),而&name[0] +1只会向后偏移1字节(步长为char类型的长度)。
绝大多数场景下数组名会被隐式转换为指向首元素的右值指针(该特性称为数组退化),但这仅仅是语法层面的转换,不代表数组本身就是指针变量。
2. char *和char[]的底层差异
char *name是独立的指针变量,它本身会占用4/8字节的存储空间(依平台指针长度而定),存储的是它指向的字符串数据的首地址。
此时你打印&name取的是指针变量自身的存储地址,&name[0]取的是它指向的字符串数据的首字符地址,二者是完全不同的内存区域,地址值自然不同。
而char name[10]是一块连续内存区域的别名,编译期就确定了它的内存位置,不存在独立的指针变量存储它的地址,这是二者最核心的区别。
3. 数组不能直接赋值的原因
你的猜测是正确的:数组名是不可修改的左值,编译器在编译阶段就已经确定了数组的内存地址(栈上数组对应栈基址的固定偏移,全局数组对应固定的虚拟地址),不允许被重新指向其他内存位置。
C语言设计时选择直接暴露底层内存布局,没有对数组做额外的封装,自然不会像高级语言那样支持自动的数组赋值操作,你如果需要拷贝数组内容,只能手动调用strcpy、memcpy等函数操作内存。
而指针是独立的普通变量,它存储的地址值可以随意修改,所以支持直接赋值操作。
4. char *作为strcat第一个参数的限制
这个说法不是绝对的,strcat对第一个参数的要求是:指向可写的、有足够剩余空间的内存区域。
- 如果你的
char *指向的是只读的字符串常量区(比如char *p = "asd";),就不能作为第一个参数,因为向只读内存写数据会触发段错误 - 如果你的
char *指向的是自己申请的堆内存,或者栈上的可写数组,只要剩余空间足够,完全可以作为strcat的第一个参数
你提到的“char *大小固定”指的是指针变量自身的存储空间固定,而它指向的内存区域大小是不固定的,编译器无法自动做边界检查,因此需要开发者自己保证目标内存可写且空间足够,避免缓冲区溢出。
内容的提问来源于stack exchange,提问作者user13991697

