tags:

views:

160

answers:

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

+3  A: 

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
+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.
GMan
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
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
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
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...
Jurily
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
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
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
@Heath: I pointed out the looping error in a comment.
Steven Sudit
@Maciej - Is your comment about NVI relating to this discussion, or did you mis-place it?
Heath Hunnicutt
@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
@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
@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
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
@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
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++.
GMan
@GMan - I think your straw-man argument stands on its own.
Heath Hunnicutt
-1 for anti-C99 trolling.
R..
@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.)
GMan
@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
@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
@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
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..
@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
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..
@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
@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.
GMan
@Heath: I am with GMan on this ->"Program C in C, program C++ in C++." :)
Prasoon Saurav
Heath Hunnicutt
@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
@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
@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
@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
@Heath : BTW, I would like to +1 your post because it is pretty correct (except the second half of your answer).
Prasoon Saurav
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
@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
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
+4  A: 

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.

Romain Hippeau
+2  A: 

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