为什么C语言中char **无法直接用字符串列表初始化创建二维数组
C语言不同字符串指针写法的运行差异底层原理
首先明确几个核心基础规则:
- C中的字符串字面量(比如
"steven")存储在进程的只读数据段,其原生类型是固定长度的char数组,赋值给指针时会自动*退化(decay)*为指向首字符的char*指针 - 指针和数组是完全不同的类型,仅在多数使用场景下,数组名会自动退化为指向首元素的指针
1. 为什么char *name = "steven";可以正常运行
char *name是一个单个的字符指针变量,本身只需要存储一个内存地址。
赋值时右侧的"steven"退化为首字符的char*指针,刚好匹配左侧指针的类型,这个操作只是把只读段中字符串的首地址赋值给栈上的name指针,类型、存储逻辑完全合法,所以可以正常运行。
2. 为什么char **names = {"steven", "randy", "ben"};无法运行
char **names是指向字符指针的指针,它本质还是单个指针变量,只能存储一个地址值(这个地址指向的内存是一个char*类型的变量)。
而右侧的初始化列表里有3个独立的字符串字面量,会退化为3个char*地址。单个指针变量根本没有额外的存储空间来存放3个地址,类型完全不匹配,编译器会直接报错。
补充:哪怕你只写一个元素
char **names = {"steven"};,在严格的C标准下也是不合法的,因为初始化列表的值类型是char*,和char**不匹配,最多只能兼容char **names = {NULL};这种空指针的特殊情况。
3. 为什么char *names[] = {"steven", "randy", "ben"};可以正常运行
char *names[]声明的是字符指针数组,类型是char* [3],本质是一个长度为3的数组,每个数组元素的类型都是char*。
初始化时,花括号里的3个字符串字面量分别退化为char*指针,刚好依次赋值给数组的3个元素,数组会在栈上分配对应3个指针大小的存储空间来存放这3个地址,类型完全匹配,所以可以正常运行。
常见误区说明
很多人混淆char**和char*[],是因为当你把char*[]类型的数组名作为参数传给函数、或者赋值给指针变量时,数组名会自动退化为指向首元素的指针——数组首元素是char*类型,所以退化后的类型就是char**。
但这个退化是使用时的隐式转换,不代表两种类型等价:char*[]是数组,本身持有多个指针的存储空间;char**是单个指针,本身只存一个地址,必须自己手动申请对应的数组空间之后才能像数组一样使用,比如:
// 手动申请存储3个char*的空间,char**才能正常存储多个字符串指针 char **names = malloc(3 * sizeof(char*)); names[0] = "steven"; names[1] = "randy"; names[2] = "ben";
内容的提问来源于stack exchange,提问作者wrosen01
相关产品推荐
相关产品推荐

