6

The following is accepted as valid c code by gcc version 6.3:

char white[] = { 'a', 'b', 'c' };
char blue[]  = "abc";
char *red    = "abc";

However the following fails:

 char *green = { 'a', 'b', 'c' };   // gcc error

I am sure there is a perfectly rational reason for this to be the case, but I am wondering what it is. This question is motivated by the case when having to initialize an array of bytes (so unsigned char rather than char), it is very tempting to write something like { '\x43', '\xde', '\xa0' } rather than "\x43\xde\xa0", and as soon as you forget to write my_array[] instead of *my_array, you get caught by the compiler.

3
  • 5
    Your definition of white is not equivalent to the other two, because it is missing the null-terminator (\0) at the end of the string. Commented Mar 20, 2017 at 14:35
  • @abelenky oh yes, this is a good point which I overlooked, thank you. Commented Mar 20, 2017 at 14:39
  • try char *green = { "a", "b", "c" };.... ;) Commented Mar 20, 2017 at 14:40

2 Answers 2

9

The following will produce an error

char *green = { 'a', 'b', 'c' };

Because the initializer for green isn't an array of characters as you believe. It doesn't have a type, it's just a brace-enclosed initializer list. The thing that it initializes in the previous samples (i.e. white) determines how it's interpreted. The same initialzier can be used to initialize any aggregate that is capable of holding 3 characters.

But green is a pointer, and not an aggregate, so you can't use a brace-enclosed initializer list as it's initial value.1

Now, the following two work but with very different semantics:

char blue[]  = "abc";
char *red    = "abc";

blue is an array. It will hold the same contents as the literal "abc". red is a pointer that points at the literal "abc".


  1. You can use a compound literal expression:

    char *green = (char[]){ 'a', 'b', 'c' };
    

    It tells the compiler to create an unnamed object (the life time of which depends on the scope of the declaration), that is of character array type and is initialized with those three characters. The pointer is then assigned the address of that object.

Sign up to request clarification or add additional context in comments.

3 Comments

All very true. The answer would be even better, however, if it showed how the char * declaration could be corrected by changing the initializer list into a char-array literal (as opposed to a string literal), and by discussing the significance of doing so.
@JohnBollinger - I was just typing in the info about compound literals
@StoryTeller Thank you very much for your help.
6

These three declarations

char white[] = { 'a', 'b', 'c' };
char blue[]  = "abc";
char *red    = "abc";

are different.

The first one declares a character array that contains exactly three characters corresponding to the number of the initializers.

The second one declares a character array of four characters because it is initialized by a string literal that has four characters including the terminating zero. So this character array contains a string.

The third one defined a string literal that is a character array and declares a pointer of type char * that is initialized by the address of the first character of the character array corresponding to the string literal.

You can imagine this declaration like

char unnamed = { 'a', 'b', 'c', '\0' };
char *red = unnamed;

This declaration

char *green = { 'a', 'b', 'c' };   

is invalid because the left object is a scalar and may not be initialized by a list that contains more than one initializer.

Take into account that you could use a compound literal to initialize the pointer. For example

char *green = ( char[] ){ 'a', 'b', 'c' };   

1 Comment

Thank you very much

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.