我总是在声明
char *c = "line";
与
相同char c[] = "line";
所以我做了
char **choices = { "New Game", "Continue Game", "Exit" };
这给了我一个不兼容的指针类型,其中
char *choices[] = { "New Game", "Continue Game", "Exit" };
没有。理解这个有什么帮助?
答案 0 :(得分:16)
char *c = "line";
与
相同char c[] = "line";
它与
完全相同static char hidden_C0[] = "line";
char *c = hidden_C0;
除了不能直接访问变量hidden_C0
。但是如果你转储生成的汇编语言,你会看到它(它的名称通常不是有效的C标识符,如.LC0
)。在你的数组字符串常量示例中,同样的事情正在发生:
char *choices[] = { "New Game", "Continue Game", "Exit" };
变为
char hidden_C0[] = "New Game";
char hidden_C1[] = "Continue Game";
char hidden_C2[] = "Exit";
char *choices[] = { hidden_C0, hidden_C1, hidden_C2 };
现在,这是一个特殊情况行为,只有 字符串常量。你不能写
int *numbers = { 1, 2, 3 };
你必须写
int numbers[] = { 1, 2, 3 };
这就是你不能写的原因
char **choices = { "a", "b", "c" };
或者
(你的困惑是一个常见误解的特殊情况,即数组与C中的指针“相同”。它们不是。数组是数组。数组类型的变量遭受类型衰减到a它们使用时的指针类型(几乎在每个上下文中),但在定义它们时却没有。)
答案 1 :(得分:13)
我打算写一些长篇大论,然后我想...其他人必须已经这样做了。他们有。这是一个很好的解释:
http://www.lysator.liu.se/c/c-faq/c-2.html
最简单的思考方式是当你做类似的事情时:
char *foo = "something";
你真的在做类似的事情:
char randomblob[] = "something"; char *foo = randomblob;
现在......这不是一个准确的图片(虽然我不是编译专家)。它至少可以让你以更加正确的方式思考问题。
所以,回到你的问题,如果我理解正确的事情(永远不能保证),你就不能在C中做你的例子#3。你是对的,有人可以写一个在这里做正确的事情的编译器,但gcc没有。然而,第四个例子做了“正确的事情”,并给你“一个指针数组,每个指针都指向一个const char数组”。
我曾经遇过一个将复杂的C类型翻译成英文的网页。这可能是在90年代初,但我打赌,如果你足够谷歌它会给你一个比我刚刚掀起的更准确的措辞描述。
答案 2 :(得分:3)
没关系,只需写下
char **choices = (char *[]){ "New Game", "Continue Game", "Exit" };
但是,choices
只能用于线性寻址。例如:
printf ("%s", &(*choices)[0]);
输出:New Game
printf ("%s", &(*choices)[1]);
输出ew Game
printf ("%s", &(*choices)[9]);
输出Continue Game
所以这不是一个玩笑,它是一个有效的初始化。只是另一种用法。
您还可以找到非常接近的示例here,解释复合文字概念。
答案 3 :(得分:2)
在线C标准(草案n1256):
6.7.8初始化
...
11 标量的初始值设定项应为单个表达式,可选择用大括号括起来。对象的初始值是表达式的初始值(转换后);与简单赋值相同的类型约束和转换适用,将标量的类型作为其声明类型的非限定版本。
...
16否则,具有聚合或联合类型的对象的初始值设定项应为元素或命名成员的括号内的初始值设定项。
强调补充。
char **
是标量类型,而不是聚合,因此与初始化程序{"New Game", "Continue Game", "Exit"}
不兼容。相比之下,char *[]
是聚合(数组)类型。
同样,你不能写像
这样的东西int *foo = {1, 2, 3};
因为int *
不是数组类型。
您对
的理解char *c = "line";
和
char c[] = "line";
稍微偏;他们不相同。第一种形式将字符串文字的地址复制到指针值c
。第二种形式将数组表达式"line"
的内容复制到c
指定的缓冲区。