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