char* arr[] = {"apple", "banana", "cherry"};这是字符指针数组存储字符串的实例。字符指针数组存储的应该是字符指针变量,为什么里面可以存储字符串呢?
严格来说,字符串“apple”本质上是一个匿名字符数组,可以视为数组名。
当写出字符串“apple”时,编译器会创建一个匿名字符数组,类型为 char[6],内容为{‘a’,‘p’,‘p’,‘l’,‘e’,‘\0’,},存储于程序的只读数据段(如.rodata 或常量区)。
若用于初始化字符数组(如 char arr[] = "apple";),编译器会将这个匿名数组的内容复制到新数组 arr 中。
若用于赋值给字符指针变量(如 char *p = "apple";),因为 "apple"可以视为一个数组名,而数组名在大多数情况下视为数组首元素的指针。编译器会将匿名数组首元素的地址直接赋给指针变量。也就是说char *p = "apple";等价于char *p = &(“apple”[0]);。
下图为在程序中的验证:
因为 "apple" 是匿名数组,所以它与普通数组(如 char arr[6];)的行为有显著不同:
数组名 | 字符串字面量 "apple" | 普通数组名arr |
可修改性 | 只读(修改会导致未定义行为) | 可修改(若未声明为 const) |
内存位置 | 常量区(只读段) | 栈或静态区(取决于定义位置) |
作用域和生命周期 | 整个程序生命周期 | 取决于定义位置(栈或静态区) |
数组名作指针时的类型 | const char* | char* |
字符串可以通过"apple"[0]得到第一个元素a,但是因为数组名 "apple"作为指针时的类型为const char*,其含义为字符指针指向的内容不可被修改,即字符串为一个常量。所以"apple"[0]=c;这种重新赋值的操作是不被允许的,语法上不会报错,但是运行时会导致异常,这种异常属于运行时错误的内存访问违规。
综上所述,字符串"apple"可视为一个数组名,表示首元素'a'的地址,字符'a'的地址即为字符指针,故可以赋值给字符指针数组。