开发者

C double character pointer declaration and initialization

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?


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.)


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.


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜