Строки без символа '\ 0'? - PullRequest
5 голосов
/ 13 марта 2011

Если по ошибке я определяю массив символов без '\ 0' в качестве последнего символа, что происходит потом? Я спрашиваю об этом, потому что заметил, что если я попытаюсь выполнить итерацию по массиву while (cnt! = '\ 0'), где cnt - это переменная int, используемая в качестве индекса для массива, и одновременно вывести значения cnt для мониторинга что происходит, итерация останавливается на последнем символе + 2. Дополнительные символы, конечно, случайны, но я не могу понять, почему он должен останавливаться после 2.Производит ли компилятор автоматический ввод символа «\ 0»? Ссылки на соответствующую документацию будет оценена.

Чтобы прояснить ситуацию, я привожу пример. Допустим, что массив "str" ​​содержит слово doh (без '\ 0'). Печать переменной cnt в каждом цикле даст мне это DOH + или дох ^ и т. д.

Ответы [ 6 ]

5 голосов
/ 13 марта 2011

РЕДАКТИРОВАТЬ (неопределенное поведение)

Доступ к элементам массива за пределами границ массива является неопределенным поведением.
Вызов строковых функций с чем-либо, кроме строки C, является неопределенным поведением.
Не делайте этого!

Строка AC - это последовательность байтов, оканчивающаяся на и включающая a '\0' (терминатор NUL).Все байты должны принадлежать одному и тому же объекту.


В любом случае, то, что вы видите, является совпадением!

Но это может произойти так

                        ,------------------ garbage
                        | ,---------------- str[cnt] (when cnt == 4, no bounds-checking)
memory ----> [...|d|o|h|*|0|0|0|4|...]
                  |   |   \_____/  -------- cnt (big-endian, properly 4-byte aligned)
                  \___/  ------------------ str
4 голосов
/ 13 марта 2011

Если вы определите массив символов без завершающего \0 (называемого «нулевым терминатором»), то в вашей строке этот терминатор не будет. Вы бы сделали это так:

char strings[] = {'h', 'e', 'l', 'l', 'o'};

В этом случае компилятор никогда автоматически не вставляет нулевой терминатор. Тот факт, что ваш код останавливается после «+2», является совпадением; с таким же успехом его можно остановить на +50 или где-либо еще, в зависимости от того, что в вашей памяти стоит строка \ 0 после вашей строки.

Если вы определяете строку как:

char strings[] = "hello";

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

Существуют некоторые функции, связанные со строками Си, которые автоматически добавляют нулевой терминатор. Это не то, что делает компилятор, а часть самой спецификации функции. Например, strncat () , который объединяет одну строку в другую, добавляет нулевой терминатор в конце.

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

3 голосов
/ 13 марта 2011

На языке C термин строка относится к массиву символов с нулевым символом в конце. Таким образом, педантично говоря, нет такой вещи как «строки без символа '\ 0'». Если он не заканчивается нулем, это не строка.

Теперь нет ничего плохого в том, что в нем есть простой массив символов без нулей, если вы понимаете, что это не строка. Если вы когда-нибудь попытаетесь работать с таким массивом символов, как если бы он был строкой, поведение вашей программы будет undefined . Все может случиться. Может показаться, что «работает» по некоторым магическим причинам. Или это может все время падать. На самом деле не имеет значения, что на самом деле будет делать такая программа, поскольку, если поведение не определено, программа бесполезна.

3 голосов
/ 13 марта 2011

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

  • Ваша программа продолжит чтение после конца строки, пока не найдет '\0', который только что там оказался. Существует несколько способов для появления такого символа, но ни один из них обычно не является предсказуемым заранее: он может быть частью другой переменной, частью исполняемого кода или даже частью большей строки, которая ранее была сохранена в том же буфере. Конечно, к тому времени, когда это произойдет, программа может обработать значительное количество мусора. Если вы видите много мусора, созданного printf(), то причиной является не определенная строка.

  • Ваша программа продолжит чтение после конца строки, пока не попытается прочитать адрес за пределами своего адресного пространства, что приведет к ошибке памяти (например, страшная «ошибка сегментации» в системах Linux).

  • При копировании через строку в вашей программе не хватит места, что снова приведет к ошибке памяти.

И, нет, компилятор C обычно не будет делать ничего, кроме того, что вы указываете в своей программе - например, он не будет завершать строку самостоятельно. Это то, что делает C таким мощным и трудным для программирования.

3 голосов
/ 13 марта 2011

Это произойдет, если по совпадению байт в *(str + 5) равен 0 (как число, а не ASCII)

0 голосов
/ 13 марта 2011

Могу поспорить, что int определяется сразу после вашей строки и что int принимает только небольшие значения, так что по крайней мере один байт равен 0.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...