Где нулевой символ в пустой строке фиксированной длины?

Поэтому мне стало любопытно прочитать код C; скажем, у нас есть следующий код:

char text[10] = "";

Куда тогда компилятор C помещает нулевой символ?

Я могу думать о 3 возможных случаях

  1. В начале, а потом 9 символов чего бы то ни было в памяти
  2. В итоге так 9 символов фигня, а потом '\0' в конце
  3. Он полностью заполняет его 10 '\0'

Вопрос в том, в зависимости от того, нужно ли добавлять конечный '\0' при выполнении strncpy. Если это случай 2 и 3, то это не обязательно, но хорошая идея; и если это случай 1, то это абсолютно необходимо.

Что это?


person Electric Coffee    schedule 12.11.2016    source источник
comment
Я возьму дверь №3, Монти. И это никак не связано с тем, что делает strncpy(). Что он должен делать, это то, что он должен делать.   -  person Sam Varshavchik    schedule 12.11.2016
comment
Вы спрашиваете о компиляторе C, но отметили это как C, так и C++. Здесь есть несколько различий между C и C++, поэтому тег C++ неуместен, если это не то, о чем вы спрашиваете.   -  person    schedule 12.11.2016
comment
@hvd подумал, что я тоже добавлю туда С++, так как было бы интересно, как обрабатываются оба случая. Но ты прав; в самом тексте не упоминается C++   -  person Electric Coffee    schedule 12.11.2016
comment
Обратите внимание, что даже если бы это был случай 1, strncpy работало бы правильно, и вам не нужно было бы добавлять конечный '\0', потому что strncpy увидит байт '\0' и не будет смотреть дальше него. Если бы это был случай 2, strncy фактически обрабатывал бы мусорные байты в начале, что довольно плохо. Как уже говорили другие, это правда в случае 3, но я хотел уточнить ваше понимание случаев 1 и 2.   -  person Alok Singhal    schedule 12.11.2016
comment
@AlokSinghal дело в том, что strncpy не добавляет завершающий \0, как это делает strcpy.   -  person Electric Coffee    schedule 12.11.2016
comment
Вы используете text в качестве источника или назначения в strncpy? Если предназначение, то неважно, что оно содержит. Если вы используете text в качестве источника, то параметр len будет = 0, а strncpy скопирует '\0' из источника.   -  person Alok Singhal    schedule 12.11.2016


Ответы (3)


При вашей инициализации массив text заполняется нулевыми байтами (т. е. вариант № 3).

char text[10] = "";

эквивалентно:

char text[10] = { '\0' };

В том, что первый элемент text явно инициализируется нулем, а остальные неявно инициализируются нулем, как того требует C11, Инициализация 6.7.9, 21:

Если в списке, заключенном в фигурные скобки, инициализаторов меньше, чем элементов или членов агрегата, или если в строковом литерале, используемом для инициализации массива известного размера, меньше символов, чем элементов в массиве, оставшаяся часть агрегата должна быть инициализированы неявно так же, как объекты со статической продолжительностью хранения.

person P.P    schedule 12.11.2016

Цитирую N1256 (примерно C99), поскольку до или после соответствующих изменений в языке нет:

6.7.8 Инициализация

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

"" — это строковый литерал, состоящий из одного символа (его завершающий нулевой символ), и в этом абзаце говорится, что этот один символ используется для инициализации элементов массива, что означает, что первый символ инициализируется нулем. Здесь ничего не говорится о том, что происходит с остальной частью массива, но есть:

21 Если в списке, заключенном в фигурные скобки, инициализаторов меньше, чем элементов или членов агрегата, или в строковом литерале, используемом для инициализации массива известного размера, меньше символов, чем элементов в массиве, остаток агрегата должны быть инициализированы неявно так же, как и объекты со статической продолжительностью хранения.

В этом абзаце говорится, что оставшиеся символы инициализируются так же, как если бы они имели статическую продолжительность хранения, что означает, что остальная часть массива также инициализируется нулем.

Здесь также стоит упомянуть, если есть место на стр. 14:

В C char a[5] = "hello"; тоже вполне допустимо, и в этом случае вы также можете спросить, куда компилятор помещает нулевой символ. Ответ здесь: это не так.

person Community    schedule 12.11.2016

Строковый литерал "" имеет тип массива символов char[1] в C и const char [1] в C++.

Вы можете представить это следующим образом

В C

chat no_name[] = { '\0' };

или в C++

const chat no_name[] = { '\0' };

Когда строковый литерал используется для инициализации массива символов, все его символы используются в качестве инициализаторов. Итак, для этой декларации

char text[10] = "";

у тебя на самом деле есть

char text[10] = { '\0' };

Все остальные символы массива, у которых нет соответствующих инициализаторов (кроме первого символа text[0]), тогда они инициализируются 0.

Из стандарта C (6.7.9 Инициализация)

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

а также

21 Если в списке, заключенном в фигурные скобки, инициализаторов меньше, чем элементов или членов агрегата, или в строковом литерале, используемом для инициализации массива известного размера, меньше символов, чем элементов в массиве, остаток агрегата должны быть инициализированы неявно так же, как объекты, которые имеют статическую продолжительность хранения

и наконец

10 Если объект с автоматическим сроком хранения не инициализирован явно, его значение неопределенно. Если объект со статической или потоковой длительностью хранения не инициализирован явно, то:

— если он имеет тип указателя, он инициализируется нулевым указателем;

— если он имеет арифметический тип, он инициализируется (положительным или беззнаковым) нулем;

— если это агрегат, то каждый элемент инициализируется (рекурсивно) в соответствии с этими правилами, а любое заполнение инициализируется нулевыми битами;

- если это объединение, первый именованный элемент инициализируется (рекурсивно) в соответствии с этими правилами, а любое заполнение инициализируется нулевыми битами;

Аналогичное написано в стандарте C++.

Учтите, что в C вы можете написать, например, следующим образом

char text[5] = "Hello";
         ^^^

В этом случае массив символов не будет иметь завершающего нуля, потому что для него нет места. :) Это то же самое, как если бы вы определили

char text[5] = { 'H', 'e', 'l', 'l', 'o' };
person Vlad from Moscow    schedule 12.11.2016