数组初始化(字符、字符串等)的存储期差异及相关疑问
嘿,这个问题挺值得深究的,先直接回应Michael Walz的观点:char arr[10] = { 'H', 'e', 'l', 'l', 'o', '\0'}; 和 char arr[10] = "Hello"; 在语义效果上确实完全等价,但背后是否生成字符串字面量,得从C标准和编译器实现两个层面来看。
下面逐个解答你的疑问:
1. 用字符初始化列表的方式,会创建字符串字面量吗?
从C标准的规定来说,{ 'H', 'e', 'l', 'l', 'o', '\0' } 就是一个普通的初始化列表,它的作用是把每个字符值(包括终止符'\0')依次赋值给数组的对应元素。标准并没有强制要求编译器必须为这个初始化列表生成一个字符串字面量——编译器完全可以直接把这些字符值逐个写入数组的内存空间,不需要额外在静态存储区生成一个字面量副本。
而"Hello"作为字符串字面量,标准明确它具有静态存储期(程序运行全程都会存在),不过当你用它初始化字符数组时,编译器会把字面量的内容复制一份到数组里。这时候数组本身是可修改的(它是栈/全局区的普通数组,不是指向字面量的指针),和用字符列表初始化的数组没有区别。
简单说:两种方式得到的数组内容完全一样,且都能修改,但前者不一定会生成额外的字符串字面量,后者的字面量本身是静态存储的,但数组只是它的拷贝。
2. 用ASCII值初始化的数组,会创建字符串字面量吗?
答案和第一种情况一致:char b[10]= {72, 101, 108, 108, 111, 0}; 本质还是用初始化列表(只不过是字符对应的ASCII整数值)来初始化数组。C标准同样没有要求编译器为此生成字符串字面量,编译器会直接把这些数值写入数组元素,最终数组b的内容和前两个arr完全相同,同样是可修改的,也不会强制生成静态存储的字面量。
容易踩坑的混淆点
很多人会把char *p = "Hello";和数组初始化搞混:这里的p是指向字符串字面量的指针,字面量本身是不可修改的(修改它属于未定义行为);但数组初始化的情况,数组有自己独立的内存空间,存的是字面量的副本,所以随便改都没问题。
最后总结一下:
- 三种初始化方式得到的数组内容完全一致,都是包含"Hello"和终止符的可修改数组
- 用字符串字面量初始化时,编译器可能会生成静态存储的字面量,但数组是独立的副本;用字符/ASCII值列表初始化时,编译器通常不会生成额外的字面量,直接赋值即可
- 三个数组本身的存储期取决于定义位置(全局/静态作用域才是静态存储,栈上就是自动存储),但不管怎样都是可修改的
内容的提问来源于stack exchange,提问作者Kami Kaze

