C 双字符指针声明和初始化

发布于 2024-10-14 23:17:25 字数 354 浏览 11 评论 0原文

我总是认为该声明

char *c = "line";

相同

char c[] = "line";

与and so I did

char **choices = { "New Game", "Continue Game", "Exit" };

,其中给出了不兼容的指针类型,而

char *choices[] = { "New Game", "Continue Game", "Exit" };

没有。对理解这一点有帮助吗?

I always though that declaring

char *c = "line";

was the same as

char c[] = "line";

and so I did

char **choices = { "New Game", "Continue Game", "Exit" };

Which gives me an incompatible pointer type, where

char *choices[] = { "New Game", "Continue Game", "Exit" };

doesn't. Any help on understanding this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

趴在窗边数星星i 2024-10-21 23:17:26

在线 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指定的缓冲区。

Online C standard (draft n1256):

6.7.8 Initialization
...
11 The initializer for a scalar shall be a single expression, optionally enclosed in braces. The initial value of the object is that of the expression (after conversion); the same type constraints and conversions as for simple assignment apply, taking the type of the scalar to be the unqualified version of its declared type.
...
16 Otherwise, the initializer for an object that has aggregate or union type shall be a brace enclosed list of initializers for the elements or named members.

Emphasis added.

char ** is a scalar type, not an aggregate, and so is not compatible with the initializer {"New Game", "Continue Game", "Exit"}. By contrast, char *[] is an aggregate (array) type.

Similarly, you couldn't write something like

int *foo = {1, 2, 3};

because int * isn't an array type.

Your understanding of

char *c = "line";

and

char c[] = "line";

is slightly off; they are not the same. The first form copies the address of the string literal to the pointer value c. The second form copies the contents of the array expression "line" to the buffer designated by c.

浅浅 2024-10-21 23:17:25
char *c = "line";

char c[] = "line";

实际上相同,

static const char hidden_C0[] = "line";
char *c = (char *)hidden_C0;

只是变量 hidden_​​C0 不可直接访问。但是,如果转储生成的汇编语言,您就会看到它(它通常具有不是有效 C 标识符的名称,例如 .LC0)。在字符串常量数组示例中,发生了同样的事情:

char *choices[] = { "New Game", "Continue Game", "Exit" };

现在

const char hidden_C0[] = "New Game";
const char hidden_C1[] = "Continue Game";
const char hidden_C2[] = "Exit";

char *choices[] = { (char *)hidden_C0, (char *)hidden_C1, (char *)hidden_C2 };

,这是一种特殊情况行为,适用于字符串常量。你不能写,

int *numbers = { 1, 2, 3 };

你必须写

int numbers[] = { 1, 2, 3 };

,这就是为什么你也不能写

char **choices = { "a", "b", "c" };

(您的困惑是常见误解的一个特例,即数组与 C 中的指针“相同”。它们不是。数组就是数组。当它们被使用(几乎在所有上下文中),但不是在定义它们时使用。)

char *c = "line";

is not the same as

char c[] = "line";

it's really the same as

static const char hidden_C0[] = "line";
char *c = (char *)hidden_C0;

except that the variable hidden_C0 is not directly accessible. But you'll see it if you dump out generated assembly language (it will usually have a name that isn't a valid C identifier, like .LC0). And in your array-of-string-constants example, the same thing is going on:

char *choices[] = { "New Game", "Continue Game", "Exit" };

becomes

const char hidden_C0[] = "New Game";
const char hidden_C1[] = "Continue Game";
const char hidden_C2[] = "Exit";

char *choices[] = { (char *)hidden_C0, (char *)hidden_C1, (char *)hidden_C2 };

Now, this is a special case behavior that is available only for string constants. You cannot write

int *numbers = { 1, 2, 3 };

you must write

int numbers[] = { 1, 2, 3 };

and that's why you can't write

char **choices = { "a", "b", "c" };

either.

(Your confusion is a special case of the common misconception that arrays are "the same as" pointers in C. They are not. Arrays are arrays. Variables with array types suffer type decay to a pointer type when they are used (in almost every context), but not when they are defined.)

箹锭⒈辈孓 2024-10-21 23:17:25

嗯,他们不一样。对于大多数人来说,更容易认为它们是相同的,所以每个人都开始这样思考,直到他们遇到像上面这样的问题:-)

我本来打算写一些长篇大论的东西,但后来我想...一定有人已经这样做了。他们确实做到了。这是一个很好的解释:

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 年代初,但我敢打赌,如果你用谷歌搜索得足够多,它会给你一个比我刚刚写的更准确的措辞描述。

Well, they're not the same. It's just easier for most people to think of them as being the same so everyone starts to think that way until they run into a problem like the above :-)

I was going to write something long and winded, but then I figured... Someone else must have done this already. And they have. This is a pretty good explanation:

http://www.lysator.liu.se/c/c-faq/c-2.html

The easiest way to think about it is that when you do something like:

  char *foo = "something";

You're really doing something like:

  char randomblob[] = "something";
  char *foo = randomblob;

Now... that's not really an accurate picture (though I'm not a compiler expert). It at least lets you think about things in a slightly more correct fashion.

So, back to your problem, if I understand things right (which is never guaranteed), you can't do your example line #3 in C. You're right that someone could write a compiler that would do the right thing here, but gcc doesn't. The 4th example, however, does the "right thing" and gives you "an array of pointers that are each pointing to a const char array themselves".

I once ran across a web page that would translate a complex C type into English. That was probably in the early 90s though but I bet if you google enough it would give you a more accurate wording description than the one I just whipped up.

小瓶盖 2024-10-21 23:17:25

没关系,只要写

char **choices = (char *[]){ "New Game", "Continue Game", "Exit" };

不过,choices 可以仅用于线性寻址。例如:

printf ("%s", &(*choices)[0]); 输出:新游戏
printf ("%s", &(*choices)[1]); 输出:ew Game
printf ("%s", &(*choices)[9]); 输出: Continue Game

所以这不是一个笑话,它是一个有效的初始化。只是另一种用法。


您还可以在此处找到一个非常接近的示例,解释复合文字概念。

It's ok, just write

char **choices = (char *[]){ "New Game", "Continue Game", "Exit" };

However, choices can be used only for linear addressing. For example:

printf ("%s", &(*choices)[0]); outputs: New Game
printf ("%s", &(*choices)[1]); outputs: ew Game
printf ("%s", &(*choices)[9]); outputs: Continue Game

So it's not a joke, it's a valid initialization. Just another kind of usage.


You can also find a very close example here, explaining Compound Literals notion.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文