Braces around string literal in char array declaration valid? (e.g. char s[] = {"Hello World"})
Asked Answered
F

6

50

By accident I found that the line char s[] = {"Hello World"}; is properly compiled and seems to be treated the same as char s[] = "Hello World";. Isn't the first ({"Hello World"}) an array containing one element that is an array of char, so the declaration for s should read char *s[]? In fact if I change it to char *s[] = {"Hello World"}; the compiler accepts it as well, as expected.

Searching for an answer, the only place I found which mentioned this is this one but there is no citing of the standard.

So my question is, why the line char s[] = {"Hello World"}; is compiled although the left side is of type array of char and the right side is of type array of array of char?

Following is a working program:

#include<stdio.h>
int main() {
    char s[] = {"Hello World"};
    printf("%s", s); // Same output if line above is char s[] = "Hello World";
    return 0;
}

Thanks for any clarifications.

P.S. My compiler is gcc-4.3.4.

Forwardness answered 13/4, 2012 at 19:39 Comment(1)
I posted a similar question a few months ago: #8061846Patch
I
65

It's allowed because the standard says so: C99 section 6.7.8, §14:

An array of character type may be initialized by a character string literal, optionally enclosed in braces. Successive characters of the character string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.

What this means is that both

char s[] = { "Hello World" };

and

char s[] = "Hello World";

are nothing more than syntactic sugar for

char s[] = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', 0 };

On a related note (same section, §11), C also allows braces around scalar initializers like

int foo = { 42 };

which, incidentally, fits nicely with the syntax for compound literals

(int){ 42 }
Insulin answered 13/4, 2012 at 19:50 Comment(9)
Nearly identical text is in C++2003, clause 8.5.2.Madai
The ability to use the superfluous braces around initializers for scalar objects also supports the "universal zero initializer" idiom in C language, where the = { 0 } can be used to initialize an object of virtually any type with zeroes.Caramelize
In general, braces simply group all statements contained within them into a single, bigger, statement. This is why you don't need { } for one line if branches (or while, etc). The compiler simply looks for the next statement after the if and executes it conditionally. So, if you want two statments, just make them appear as one by surrounding them in curlies.Capital
Similar rules apply to ( ) and commas. a = (x = 1, y = 2, z = 3); will execute all the inner terms and return x as it's value, so a = 1 will be the result. However, this is not the same as {x = 1, y = 2, z = 3} which simply executes the three statements. In both cases, however, x, y, z end up as 1, 2, and 3, respectively.Capital
@DavidCowden: That is incorrect. a = (x = 1, y = 2, z = 3); will set a to 3, not 1.Sampson
@DavidCowden: That's just comma expression.Colvert
@Nawaz Yes, sorry it was late (=Capital
@David Cowden: The usage of {} in the context of initialization has absolutely no relation to their usage in the compound statement syntax.Caramelize
It's allowed because the standard says so - most used sentence in SOBituminous
S
22

The braces are optional, and the expression is equivalent to just an array of char.

You can also write this:

 int a = {100}; //ok

Demo : http://ideone.com/z0psd

In fact, C++11 generalizes this very syntax, to initialize non-arrays as well as arrays, uniformly. So in C++11, you can have these:

int a{}; //a is initialized to zero, and it is NOT an array

int b[]{1,2,3,4}; //b is an array of size 4 containing elements 1,2,3,4

int c[10]{}; //all 10 elements are initialized to zero

int *d{}; //pointer initialized to nullptr

std::vector<int> v{1,2,3,4,5}; //vector is initialized uniformly as well.
Sampson answered 13/4, 2012 at 19:45 Comment(0)
F
4

Any variable in (int, char, etc.) is just an array of length 1.

char s = {0};

works as well.

Far answered 13/4, 2012 at 19:46 Comment(0)
H
2

I might be wrong, but I think this is not an array of arrays of chars, but a block contains an array of chars. int a = {1}; may work as well.

Homestead answered 13/4, 2012 at 19:45 Comment(0)
R
1

[...] In fact if I change it to char *s[] = {"Hello World"}; the compiler accepts it as well, as expected

The compiler accepets it,because actually, you're making an array 2D of undefined size elements,where you stored one element only,the "Hello World" string. Something like this:

char* s[] = {"Hello world", "foo", "baa" ...};

You can't omit the bracets in this case.

Rhombus answered 13/4, 2012 at 20:19 Comment(0)
R
1

This is allowed by the C++ standard as well, Citation:

[dcl.init.string] §1

An array of narrow character type ([basic.fundamental]), char16_t array, char32_t array, or wchar_t array can be initialized by a narrow string literal, char16_t string literal, char32_t string literal, or wide string literal, respectively, or by an appropriately-typed string literal enclosed in braces ([lex.string]). [snip]

Regulable answered 29/7, 2016 at 10:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.