为啥 C 双星号不能用于创建二维数组?

Posted

技术标签:

【中文标题】为啥 C 双星号不能用于创建二维数组?【英文标题】:Why doesn't the C double asterisk work for creating a 2D array?为什么 C 双星号不能用于创建二维数组? 【发布时间】:2021-11-05 06:09:49 【问题描述】:

为什么会这样:

char *name = "steven";

但这不是:

char **names = "steven", "randy", "ben";

或者,为什么会这样:

char *names[] = "steven", "randy", "ben";

但是,这又不是:

char **names = "steven", "randy", "ben";

【问题讨论】:

TLDR:因为char **names 不引用二维数组,不管你被告知什么。见Correctly allocating multi-dimensional arrays 这能回答你的问题吗? Double pointer vs array of pointers(**array vs *array[]) 谢谢,是的,这两个链接都很有帮助。所以当你有 char 那么当你有 char *names[] = "bob", ... 时,names 是一个指针吗? 不,[] 表示names 是一个数组,char * 表示该数组包含指向char 的指针 【参考方案1】:

char **p 不是二维数组,它是指向字符指针的指针。但是,您可以有更多的指针和更多的字符跟随,类似于一种 2D 字符结构的模型。

C 编译器将 "steven" 解释为一维字符数组,因为大括号是可选的(标准章节 6.7.9 第 14 段)。

正如您所尝试的,您可以通过char *p[] 声明一个指向字符的指针数组。

但是如果你想要那个指针(指向字符的指针),你需要告诉你的编译器。数组的地址可以赋值给指针。

char **p = (char *[]) "steven", "randy", "ben", ;

附加说明:由于字符串文字是不可变的,因此您最好为字符添加const。由于这些未命名的字符串字面量的地址也是常量,因此您可以提供另一个地址。

const char * const *p = (const char * const []) "steven", "randy", "ben", ;

【讨论】:

谢谢。我是否正确地说 (char *[]) "steven", "randy", "ben", 是类型转换? 嗯,它是一个复合字面量,参见第 6.5.2.5 章。该标准将其与演员表区分开来。 这与演员阵容大不相同。它创建(分配内存)一个对象;该对象具有定义的生命周期,您必须注意这一点。【参考方案2】:

我也想知道,如果我能以最简单的方式回答你呢。

你为什么感到困惑?

一个指向整数的简单指针,例如分配8 个单元,其作用方式与一个维数为8 个单元的数组相同。 您看不到的唯一区别是分配了 8 个单元的指针位于称为 HEAP 的内存部分,而 int tab[8] 类型的变量在 STACK 上分配。 确实,由于单元格在内存中是相互链接的,所以很容易想象,发送第一个单元格地址的指针和数组是一回事。

为什么它在其他情况下不起作用

但是,当想到将 (** 和 [][]) 关联起来时 我们以 int ** 为例;

int **tab;

tab = malloc(sizeof(int *) * 4);
//secure malloc do not forget
for (int i = 0; i < 4; i++)

   tab[i] = malloc(sizeof(int) * 3);
   //secure malloc do not forget

还有一个

int[4][3];

你有问题。 想象一下,double 数组类型在内存中跟随其自身,因为这正是数组的原理。

虽然双指针首先分配了 4 个 int * 类型的单元(它们在内存中相互跟随),然后这 4 个单元的每个指针都指向一个由 3 个相互跟随的 int 组成的内存区域。但整件事在记忆中并没有互相跟随!

您可能感兴趣的方式

您可以做的一件事是创建一个int ptr(*)[3]; 它可以指向一个大小为 3 的数组的第一个元素,例如数组 [4][3] 的地址。

【讨论】:

【参考方案3】:

标量对象的初始化程序不能包含多个项目。

6.7.9 初始化 ...约束 2     任何初始化程序都不应尝试为不包含在实体中的对象提供值 正在初始化。 ... 11     标量的初始值设定项应该是一个表达式,可选地用大括号括起来。这 对象的初始值是表达式的初始值(转换后);同类型 适用于简单赋值的约束和转换,采用标量的类型 成为其声明类型的非限定版本
C 2011 Online Draft

char **names 声明了一个单一的标量对象,而不是一个数组,因此它的任何初始化程序必须只包含一个项目。该初始值设定项可以是单个字符串 ("steven"),可选择用大括号 ( "steven" ) 括起来。但是,它可能不是初始化器的列表

【讨论】:

以上是关于为啥 C 双星号不能用于创建二维数组?的主要内容,如果未能解决你的问题,请参考以下文章

如果行和列的差大于 1,为啥我不能打印二维数组?

为啥代码不能打印这个二维数组的元素?

C中结构体内有一个成员是二维数组,可以直接赋值另一个一维数组吗?

C语言数组为啥按行优先存储

C语言程序设计:求二维数组中最大元素值及其行列号

为啥js二维数组传给后台接收到的数据变成了字符串