Брекеты вокруг строкового литерала в объявлении массива char действительны? (например, char s[] = {"Hello World"})

Случайно обнаружил, что линия char s[] = {"Hello World"}; правильно компилируется и, кажется, обрабатывается так же, как char s[] = "Hello World";, Не первый ({"Hello World"}) массив, содержащий один элемент, который является массивом char, поэтому объявление для s должно читать char *s[]? На самом деле, если я изменю это на char *s[] = {"Hello World"}; компилятор также принимает это, как и ожидалось.

В поисках ответа, единственное место, где я упомянул это упоминание об этом, это не цитирование стандарта.

Итак, мой вопрос, почему линия char s[] = {"Hello World"}; компилируется, хотя левая сторона имеет тип array of char и правая сторона имеет тип array of array of char?

Ниже приводится рабочая программа:

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

Спасибо за любые разъяснения.

PS Мой компилятор gcc-4.3.4.

6 ответов

Решение

Это разрешено, потому что стандарт гласит: C99 раздел 6.7.8, §14:

Массив символьного типа может быть инициализирован литералом символьной строки, необязательно заключенным в фигурные скобки. Последовательные символы литерала символьной строки (включая завершающий нулевой символ, если есть место или массив имеет неизвестный размер) инициализируют элементы массива.

Это означает, что оба

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

а также

char s[] = "Hello World";

не более чем синтаксический сахар для

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

В соответствующем примечании (тот же раздел, §11), C также допускает скобки вокруг скалярных инициализаторов, таких как

int foo = { 42 };

что, кстати, хорошо вписывается в синтаксис составных литералов

(int){ 42 }

Скобки необязательны, а выражение эквивалентно просто массиву символов.

Вы также можете написать это:

 int a = {100}; //ok

Демо: http://ideone.com/z0psd

По факту, C++11 обобщает этот самый синтаксис для равномерной инициализации как массивов, так и массивов. Так в C++11Вы можете иметь это:

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.

Любая переменная в (int, charи т. д.) это просто массив длины 1.

char s = {0};

работает так же.

Я могу ошибаться, но я думаю, что это не массив массивов символов, а блок содержит массив символов. int a = {1}; может работать так же.

[...] На самом деле, если я изменю его на char *s[] = {"Hello World"}; компилятор также принимает это, как и ожидалось

Компилятор принимает это, потому что на самом деле вы создаете массив 2D с элементами неопределенного размера, где вы сохранили только один элемент, "Hello World" строка. Что-то вроде этого:

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

Вы не можете опустить bracets в этом случае.

Это допускается также стандартом C++, Citation:

[dcl.init.string] §1

Массив с узким символьным типом ([basic.fundamental]), массив char16_t, массив char32_t или массив wchar_t может быть инициализирован узким строковым литералом, строковым литералом char16_t, строковым литералом char32_t или широким строковым литералом, соответственно или строковый литерал подходящего типа, заключенный в фигурные скобки ([lex.string]). [Надрез]

Другие вопросы по тегам