3
char *names[] = {
        [3] = "foo", 
        [1] = "bar", 
        [0] = "man"};

int i;
for (i=0; i<sizeof(names)/sizeof(char); i++)
{
    puts(names[i]);
}

What are the function of the brackets in the above declaration? Also, why does the resulting loop iterate 3 times instead of 4 and produce this output:

man

bar

jruizaranguren
  • 12,679
  • 7
  • 55
  • 73
zer0stimulus
  • 22,306
  • 30
  • 110
  • 141

3 Answers3

4

The following definition shows how you can use designated initializers to skip over elements of the array that you don't want to initialize explicitly:

static int number[3] = { [0] = 5, [2] = 7 };

The array number contains the following values: number[0] is 5; number[1] is implicitly initialized to 0; number[2] is 7.

Heath below, describes the effect of your for loop, so I will not repeat.

caf
  • 233,326
  • 40
  • 323
  • 462
Romain Hippeau
  • 24,113
  • 5
  • 60
  • 79
3

The numbers in brackets are the indices of the initializers. This is a C99 feature.

Given that your example code does use this blemish, the reason you receive the output you do is that "foo" is stored in names[3], while NULL is stored in names[2]. Your program crashes when it attempts to puts(names[2]) which is the same as puts(NULL).

Your loop would otherwise iterate to 16 or 32 iterations -- you are dividing by sizeof(char) for the array element size, and you mean to use sizeof(char *).

Better to use this macro:

#define DIMENSION_OF (a) (sizeof(a)/sizeof(a[0]))

I suggest never using any C99-specific features, such as these "designated initializers."

There is a reason that most of the answers you received on this question were confused as to why your loop only output two strings rather than four. That reason is that C99 is not widely recognized by other programmers.

There are several reasons that most programmers aren't familiar with C99's more distinctive features. A frequently cited reason is that C99 is more incompatible with C++ than ANSI C, and makes the possibility of future conversion to C++ more difficult. My personal complaint with C99 also makes extensions to ANSI C which are superfluous. An example of a superfluous addition is the example from C99 that you have provided. Don't use "designated inits." Do refer to the American National Standards Institute C Standard. Do not refer to the International Standards Organization C99 document.

Most of the features which are "nice to have" form C99 were already available as extensions in all major compilers. Declaring a variable in the for-init-statement is an example of a non-ANSI-C-standard feature which is widely supported. The complex built-in type is an example of a non-ANSI-C-standard feature that is not widely supported.

Heath Hunnicutt
  • 18,667
  • 3
  • 39
  • 62
  • 6
    +1 for the first part, but -1 for the last part. What kind of argument is "it's not compatible with C++" against C99? Who cares? C is not C++, therefore don't use C? C99 provides fixes and improvements to the language, use it if you can. – GManNickG Aug 07 '10 at 17:54
  • 1
    If you consider "complex" type, hexadecimal init of floats, designated inits, and many other C99 feature to be other than pimples and warts, I don't want to be your friend, anyway. C99 provides some good but mostly *damage* to the heritage of the C language. C99 is bad. Note that it is so bad that nobody here but me has the correct answer for his early loop termination. SO denizens can't even *read* C99 properly. C99 is bad. – Heath Hunnicutt Aug 07 '10 at 18:00
  • As for it not being compatible with C++... I don't like C++, either. But the fact remains, if someone introduces C99-specific warts into their code, later they will have a harder time converting that source to compile as C++. This is not *my* reason for disdaining C99, but it is a reason I have often seen mentioned on SO by people who consider that a big deal. As I see it, C++ lovers have good reason to dislike C99 for that reason; meanwhile, C lovers have great reason to dislike C99 for reasons explained above. – Heath Hunnicutt Aug 07 '10 at 18:03
  • I admit is strange that I gave two "chief" reasons. I do think the damage to C reason is much more serious than the issue with C++ compatibility. – Heath Hunnicutt Aug 07 '10 at 18:04
  • 2
    Sigh. Do you really want to force C++ coders to invent your wheel again just because you like an incompatible feature? Most of C++'s power comes from being able to use C libraries, you know... – György Andrasek Aug 07 '10 at 18:09
  • 1
    Nice tips, but if it indeed is a homework I suggest writing a letter to OP's professor :). And now seriously. I can perfectly understand that confusion is a bad thing, but if we want any progress it's inevitable. Do we want any progress? There are two options. We can frown upon using new features and try to stay in place (which won't work anyway) or simply make the transition fast so the pain is bearable. – Maciej Hehl Aug 07 '10 at 18:12
  • Yesterday I stumbled upon a question about NVI http://stackoverflow.com/questions/3427047/should-the-nvi-idiom-be-used-for-simple-interface-classes. Herb Sutter's article is from 2001. I was pretty sure Marshall Cline in his C++FAQ Lite argued to never use private virtuals, because it confuses people. I had to check and lo-and-behold it was changed. But the revision was in 2009. It took an expert 8 years to realise he was promoting a bad practice. Who looks dumb now? – Maciej Hehl Aug 07 '10 at 18:16
  • Maciej - We want progress, but not licentiousness. In the history of C, the standards such as ANSI C codified what was already practiced and had been well-studied. Same with C++. With C99, the ISO body took it upon themselves to add new stuff that nobody was already practicing and which were not well-studied. Such crap as hexadecimal initializers for floats do not belong in a portable language. Designated inits clearly harm the language. Witness the lack of SO who can read it... – Heath Hunnicutt Aug 07 '10 at 18:19
  • @Maciej - Is your comment about NVI relating to this discussion, or did you mis-place it? – Heath Hunnicutt Aug 07 '10 at 18:22
  • @Steven: The C99-specific reason his loop terminates early is the mis-use of designated inits. The error in looping you pointed out would otherwise have caused his loop to iterate *too many* times, not too few. It is also not a C99-specific coding error; but the mistake surrounding the use of designate-inits, specifically the initialization of element 2 as `NULL`, is the C99-specific coding error. And, as I wrote, I see that I am the only poster to have describe that part of the OP's problem. Thus, I maintain that SO cannot even read C99. – Heath Hunnicutt Aug 07 '10 at 18:30
  • @Heath Yes. I wanted to illustrate that sometimes 20 years is not enough to really find out how to use a language (at least a language like C++) and there is no other way, but to give a try to different ideas, and that, discouraging people from using features because they confuse people can look silly after 10 years, so you know what you are risking. – Maciej Hehl Aug 07 '10 at 18:33
  • @Maciej -- Ha ha thanks for your 'warning'. OMG/LOL. As for trying different ideas, of course I agree. As for standardizing new ideas before they have been tried -- that is what I blame the ISO C99 committee for. They standardized new ideas that had not been vetted. Those do not belong in a "standard" unless the committee has an ego problem... Why anybody would suggest that experimental features belong in a *standard* is beyond me. Feeling defensive about a European standard or something? – Heath Hunnicutt Aug 07 '10 at 18:36
  • Yes, I stopped at the first loop-related error I ran into. It's odd that the OP said nothing about crashing, though. – Steven Sudit Aug 07 '10 at 18:45
  • @Steven - I agree it is odd the OP said nothing about crashing. I wonder about that, too. But, since `sizeof(char)` is 1 and `sizeof(char *)` is probably 4 or 8, the error with finding the array dimension should have resulted in *too many* attempted iterations by a factor of 4 or 8. But, yeah, I also wonder why no mention of the bus error. – Heath Hunnicutt Aug 07 '10 at 18:51
  • 2
    As far as I can tell you're just saying "I don't need these features, so it's bad." Then don't use the features. And seriously, anyone who says "Don't use this variant of C because it's not 'compatible' with C++" is, frankly, a moron. Program C in C, program C++ in C++. They aren't the same language, they aren't translations of one another, they aren't meant to be easily exchanged, etc. You wouldn't say the same thing about Java versus C#, don't say it about C and C++. – GManNickG Aug 07 '10 at 19:04
  • @Heath: So are you going to respond or just claim straw-man without substantiating the claim? Here, I can do it too: I think your straw-man argument stands on its own. (Does nothing.) – GManNickG Aug 07 '10 at 19:35
  • @GMan - I didn't make a straw-man argument, but your Java/C# argument is a case in point. And it is so hilarious, that, no, I'm not going to respond. It defeats itself well enough as-is. – Heath Hunnicutt Aug 07 '10 at 19:58
  • 1
    @R.. I have given valid reasons to never use C99, and you have only invoked the word "trolling" without introducing a single rational statement. So, pphhht, to you. – Heath Hunnicutt Aug 07 '10 at 19:59
  • @Heath: Well, when we're unclear about the question, a shotgun approach to the answer is probably best. Between the various comments, I think we've addressed all of the issues. – Steven Sudit Aug 07 '10 at 20:38
  • Giving "valid reasons" not to use a language as 75% of an answer to a question about what a certain construct in that language means is not answering the question; it's trolling. – R.. GitHub STOP HELPING ICE Aug 07 '10 at 21:15
  • @R... Well now THAT response is extremely disingenuous, by which I mean you are a liar. When you wrote your "trolling" remark, you know full well that my well-reasoned anti-C99 position made up only 25% of the answer. In response to your "trolling" remark, I *expanded* that part of the answer. And of course you knew that when you wrote your little lie. – Heath Hunnicutt Aug 07 '10 at 22:50
  • By the way, your use of "ANSI C" to mean "old C" is incorrect. ANSI is aligned with ISO. If you mean C89/C90, you should say so. – R.. GitHub STOP HELPING ICE Aug 08 '10 at 03:43
  • @GMan: Whoa!! I've never seen you attacking someone personally. What Heath thinks is his personal opinion and you cannot change someone's mindset so easily. – Prasoon Saurav Aug 08 '10 at 04:33
  • @Prasoon: I'm not doing any such thing. I'm pointing out flaws in the arguments, which is independent of the person. In fact, if I were actually attacking someone instead of their argument, I'd be committing an ad hominem attack, a fallacious form of argument. – GManNickG Aug 08 '10 at 05:50
  • 1
    @Heath: I am with GMan on this ->"Program C in C, program C++ in C++." :) – Prasoon Saurav Aug 08 '10 at 05:57
  • @Prasoon: It is sorry to hear that you are with a dummy. Regarding C/C++ vs. Java/C# -- there is no, and never has been, a proggram named "JavaFront" which translates C# into Java. Compare with AT&T's (BS's) "cfront", the first ever implementation of C++, which translated C++ into C. That is the very evolution of C++ -- it stems from C. Thus, it is imminently reasonable to adopt C coding guidelines which attempt to minimize deviation from the evolved language. The relationship between Java and C# is completely different. When you code in C, code in C. When you code in C99, code in C99. – Heath Hunnicutt Aug 08 '10 at 15:40
  • 1
    @Gman -- Actually, your ad hominem attack was referring to me as a "moron." Your argument consisted of a mindless mantra, an ad hominem attack, a straw-man argument, then denial. As a matter of fact, I'm happy to call you a moron, too: MORON. – Heath Hunnicutt Aug 08 '10 at 15:45
  • @Heath : `When you code in C, code in C. When you code in C99, code in C99`. Modern day C is all about C99. :) – Prasoon Saurav Aug 08 '10 at 15:50
  • @Prasoon: If that were true, many, many SO posters would have recognized the problem with OP's code. In fact, the majority erroneously focused on `sizeof(char)`... If C99 is so widely accepted, why is it that programmers aren't actually familiar with it? – Heath Hunnicutt Aug 08 '10 at 16:12
  • 1
    @Heath: Infact many of the posters here at SO or comp.lang.c are pretty confortable with C99. Apart from that modern compilers have a decent C99 support (except Visual C which still only supports C89). If you would have given the same opinion at comp.lang.c guys there would have said much much more against your post. :) – Prasoon Saurav Aug 08 '10 at 16:31
  • 1
    @Heath : BTW, I would like to +1 your post because it is pretty correct (except the second half of your answer). – Prasoon Saurav Aug 09 '10 at 02:03
  • There is nothing at all wrong with either C99 designated initalisers (in particular the struct member initalisers are *very* useful, and help to make code less fragile), or with hexadecimal floating point constants (they're no less portable than decimal constants - base 10 is no more privileged than base 16). The rule about uninitialised elements being `NULL` dates back to C89 anyway - eg `char *a[5] = { "foo", "bar" };` - and it is *just* as poorly understood on SO even though it is 30 years old and not 20. – caf Aug 09 '10 at 02:39
  • @caf - Thanks for that. I don't see evidence that partial initialization is *just as* poorly understood on SO. I agree it seems to be poorly understood, but not to the same pervasive extent. For example, you can find questions about that answered on SO. – Heath Hunnicutt Aug 09 '10 at 05:20
  • Well, you can find questions about designated initalizers correctly answered too, like [this one](http://stackoverflow.com/questions/3374446/what-happens-to-fields-not-named-by-a-designated-initializer). – caf Aug 09 '10 at 06:19
2

It declares names to be an array (whose size is determined by the compiler) of pointers to char, with initialization that also determines the size of the array; the initialization "decides" explicitly the index of specific pointer; e.g. man is at index 0, foo at index 3... The final size is given by the bigger index, and all values with indexes not explicitly given are set to null.

It should be sizeof(char *) as already said. The loop prints the content; if the number of elements in the array is 3, the index must go from 0 to 2, (2<3 but 3<3 is false) since index-base in C is 0.

ShinTakezou
  • 9,432
  • 1
  • 29
  • 39