C双字符指针声明和初始化
我总是这样宣告
char *c = "line";
和…一样
char c[] = "line";
所以我做到了
char **choices = { "New Game", "Continue Game", "Exit" };
这给了我一个不兼容的指针类型,在哪里
char *choices[] = { "New Game", "Continue Game", "Exit" };
没有。 理解这个有什么帮助吗?
嗯,他们不一样。 大多数人认为它们是相同的更容易,所以每个人都开始这么想,直到遇到如上所述的问题:-)
我打算写一些长篇大论,然后我想…其他人必须已经这样做了。 他们有。 这是一个很好的解释:
http://www.lysator.liu.se/c/c-faq/c-2.html
考虑它的最简单方法是,当你做以下事情时:
char * foo =“某事”;
你真的在这样做:
char randomblob [] =“某事”; char * foo = randomblob;
现在……这不是一个真正准确的图片(尽管我不是编译专家)。 它至少可以让你以更加正确的方式思考问题。
所以,回到你的问题,如果我理解正确的事情(从来没有保证),你就不能在C中做你的示例行#3。你是对的,有人可以编写一个能在这里做正确的事情的编译器,但是gcc没有。 然而,第四个例子做了“正确的事情”,并给你“一个指针数组,每个指针指向一个const char数组本身”。
我曾经遇过一个将复杂的C类型翻译成英文的网页。 这可能是在90年代初,但我敢打赌,如果你足够谷歌它会给你一个比我刚刚掀起的更准确的措辞描述。
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中的指针“相同”。它们不是。数组是数组。数组类型的变量在使用时会遭受类型衰减到指针类型(几乎每个上下文),但不是在定义时。)
没关系,只需写
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
所以这不是一个玩笑,它是一个有效的初始化。 只是另一种用法。
您还可以在此处找到一个非常接近的示例,解释复合文字概念。
在线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";
有点偏; 他们不一样。 第一种forms将字符串文字的地址复制到指针值c
。 第二种forms将数组表达式"line"
的内容复制到c
指定的缓冲区。