Инициализация массива символов с явным размером и инициализация больше, чем размер

Я читал код и столкнулся со следующим:

int function(){
    char str[4] = "ABC\0";
    int number;

    /* .... */
}

Обычно, когда вы пишете строковый литерал для инициализации массива символов, строка должна неявно заканчиваться нулем, верно? Что происходит в этом случае? Распознает ли компилятор '\0' в строковом литерале и делает ли это нулевым ограничителем? или он переполняется на целое число? Что-то не так с этой формой?


person 9a3eedi    schedule 18.04.2014    source источник
comment
Чего вы действительно хотите, так это char str[] = "ABC";   -  person David Heffernan    schedule 18.04.2014
comment
Я обычно так и делаю, но это не мой код. Я читал чужой код, и это появилось, и я начал задаваться вопросом, не вызовет ли это у меня проблемы   -  person 9a3eedi    schedule 19.04.2014


Ответы (2)


Стандарт C99 6.7.8.14 говорит

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

Это означает, что следующие утверждения эквивалентны.

char str[4] = "ABC\0";
// equivalent to
char str[4] = "ABC";
// equivalent to
char sr[4] = {'A', 'B', 'C', '\0'};

Так что нет ничего плохого в первом утверждении выше. Как прямо указано в стандарте, для инициализации массива в качестве размера массива используется только то количество символов в строковом литерале. Обратите внимание, что строковый литерал "ABC\0" на самом деле содержит пять символов. '\0' такой же, как и любой другой персонаж, так что все в порядке.

Однако обратите внимание, что есть разница между

char str[4] = "ABC\0";
// equivalent to 
char str[4] = {'A', 'B', 'C', '\0'};


char str[] = "ABC\0";  // sizeof(str) is 5 
// equivalent to
char str[] = {'A', 'B', 'C', '\0', '\0'};

Это связано с тем, что строковый литерал "ABC\0" содержит 5 символов, и все эти символы используются при инициализации str, когда размер массива str не указан. В отличие от этого, когда размер str явно указан как 4, то только первые 4 символов литерала "ABC\0" используются для его инициализации, как ясно указано в приведенном выше абзаце стандарта.

person ajay    schedule 18.04.2014
comment
Отличный ответ. Спасибо! Эквивалентность помогает мне понять - person 9a3eedi; 19.04.2014
comment
Как ABC\0 имеет 5 символов? \0 один символ? Или это два символа \0 для инициализатора? - person 3366784; 21.09.2017
comment
Строка представляет собой постоянный массив символов, оканчивающийся нулем. Таким образом, помимо \0, который является частью самой строки, есть еще \0, завершающий строку нулем. - person ajay; 21.09.2017

Если код:

char str[3] = "ABC";

Это нормально в C, но массив символов str не является строкой, потому что он не завершается нулем. См. Часто задаваемые вопросы по C: Is char a[3] = "abc"; законно? Что это значит? подробнее.

В вашем примере:

char str[4] = "ABC\0";

Последний символ массива str оказывается равным '\0', так что все в порядке, и это строка.

person Yu Hao    schedule 18.04.2014
comment
Я не знал, что это допустимо в C, но недопустимо в C++. +1 от меня - person Marco A.; 18.04.2014
comment
@Marco Да, это одно из различий между C и C++. Тот же код недействителен в C++. - person Yu Hao; 18.04.2014
comment
Интересный. Возможно, мне понадобится перенести мой код C на компилятор C++, поэтому лучше помнить об этом. - person 9a3eedi; 19.04.2014