Строка AC - это массив символов, заканчивающийся нулевым терминатором .
Все символы имеют значение таблицы символов. Терминатор null - это значение символа 0
(ноль). Используется для обозначения конца строки. Это необходимо, поскольку размер строки нигде не сохраняется.
Поэтому каждый раз, когда вы выделяете место для строки, вы должны включать достаточно места для нулевого символа-терминатора. Ваш пример не делает этого, он только выделяет место для 5 символов "hello"
. Правильный код должен быть:
char str[6] = "hello";
Или эквивалентно, вы можете написать самодокументируемый код для 5 символов плюс 1 нулевой терминатор:
char str[5+1] = "hello";
При динамическом выделении памяти для строки во время выполнения также необходимо выделить место для нулевого терминатора:
char input[n] = ... ;
...
char* str = malloc(strlen(input) + 1);
Если вы не добавляете нулевой терминатор в конец строки, библиотечные функции, ожидающие строку, не будут работать должным образом, и вы получите ошибки «неопределенного поведения», такие как вывод мусора или сбой программы.
Наиболее распространенный способ , чтобы написать нулевой терминатор символ в C является использование так называемой «восьмеричное последовательность», глядя , как это: '\0'
. Это на 100% эквивалентно написанию 0
, но \
служит самодокументированным кодом, утверждающим, что ноль явно является нулевым терминатором. Код, такой как if(str[i] == '\0')
, проверит, является ли определенный символ нулевым терминатором.
Обратите внимание, что термин «нулевой терминатор» не имеет ничего общего с нулевыми указателями или NULL
макросом! Это может сбивать с толку - очень похожие имена, но очень разные значения. Вот почему нулевой терминатор иногда называют NUL
одним L, не путать с NULL
нулевыми указателями. См. Ответы на этот вопрос SO для получения дополнительной информации.
В "hello"
вашем коде называется строковым литералом . Это следует рассматривать как строку только для чтения. В ""
синтаксическом означает , что компилятор добавит нулевой терминатор в конце строки буквальных автоматически. Таким образом, если вы распечатаете, sizeof("hello")
вы получите 6, а не 5, потому что вы получите размер массива, включая нулевой терминатор.
Он компилируется чисто с GCC
Действительно, даже не предупреждение. Это происходит из-за тонкой детализации / недостатка в языке C, который позволяет инициализировать символьные массивы строковым литералом, который содержит ровно столько символов, сколько есть места в массиве, а затем молча отбросить нулевой терминатор (C17 6.7.9 / 15). Язык преднамеренно ведет себя так по историческим причинам, см. Подробности в разделе Непоследовательная диагностика gcc для инициализации строки . Также обратите внимание, что здесь C ++ отличается и не позволяет использовать этот трюк / недостаток.
char str[] = "hello";
случай.char *str = "hello";
...str[0] = foo;
sizeof
на его использование в параметре функции, особенно когда он определен как массив.Из стандарта C (7.1.1 Определения терминов)
В этой декларации
строковый литерал
"hello"
имеет внутреннее представление типапоэтому он имеет 6 символов, включая завершающий ноль. Его элементы используются для инициализации массива символов,
str
который резервирует пространство только для 5 символов.Стандарт C (противоположный стандарту C ++) позволяет такую инициализацию массива символов, когда конечный ноль строкового литерала не используется в качестве инициализатора.
Однако в результате массив символов
str
не содержит строку.Если вы хотите, чтобы массив содержал строку, вы можете написать
или просто
В последнем случае размер массива символов определяется из числа инициализаторов строкового литерала, равного 6.
источник
Можно ли считать все строки массивом символов ( Да ), можно ли считать все массивы символов строками ( Нет ).
Почему бы нет? и почему это важно?
В дополнение к другим ответам, объясняющим, что длина строки нигде не хранится как часть строки, и ссылкам на стандарт, где определяется строка, оборотной стороной является «Как функции библиотеки C обрабатывают строки?»
Хотя массив символов может содержать одинаковые символы, он представляет собой просто массив символов, если за последним символом не стоит завершающий нулем символ. Этот завершающий нуль символ - это то, что позволяет массиву символов считаться (обрабатываться как) строкой.
Все функции в C, которые ожидают строку в качестве аргумента, ожидают, что последовательность символов будет оканчиваться нулем . Почему?
Это связано с тем, как работают все строковые функции. Поскольку длина не включена как часть массива, строковые функции сканируют в массиве до тех пор, пока не будет найден нуль-символ (например,
'\0'
- эквивалент десятичного числа0
). Смотрите таблицу ASCII и описание . Независимо от того, используете ли выstrcpy
,strchr
,strcspn
и т.д .. Все строковые функции полагаются на NUL оконечного характера присутствуя определить , где конец этой строки есть.Сравнение двух похожих функций из
string.h
подчеркивает важность нулевого завершающего символа. Взять, к примеру:strcpy
Функция просто копирует байты изsrc
кdest
до NUL оконечного символ не найдено рассказывая ,strcpy
где остановить копирование символов. Теперь возьмите похожую функциюmemcpy
:Функция выполняет аналогичную операцию, но не считает или требует, чтобы
src
параметр был строкой. Так какmemcpy
приsrc
копировании байтов не удается просто выполнить перемотку вперед доdest
тех пор, пока не будет достигнут нулевой завершающий символ, ему требуется явное количество байтов для копирования в качестве третьего параметра. Этот третий параметр обеспечиваетmemcpy
ту же информацию о размере, которуюstrcpy
можно получить, просто сканируя вперед, пока не будет найден нулевой завершающий символ.(который также подчеркивает, что идет не так
strcpy
(или любую функцию, ожидающую строку), если вы не можете обеспечить функцию строкой с нулевым символом в конце - он понятия не имеет, где остановиться, и с удовольствием прыгнет через оставшуюся часть вашего сегмента памяти вызывая неопределенное поведение до тех пор, пока nul-символ просто не будет найден где-то в памяти - или не произойдет ошибка сегментации)Вот почему функциям, ожидающим строку с нулевым символом в конце, должна быть передана строка с нулевым символом в конце и почему это важно .
источник
Наглядно ...
Думайте о массиве как о переменной (содержит вещи) и о строке как о значении (может быть помещено в переменную).
Они, конечно, не одно и то же. В вашем случае переменная слишком мала, чтобы содержать строку, поэтому строка обрезается. («заключенные в кавычки» в C имеют неявный нулевой символ в конце.)
Однако возможно сохранить строку в массиве, который намного больше, чем строка.
Обратите внимание, что обычные операторы присваивания и сравнения (
=
==
<
и т. Д.) Не работают так, как вы могли бы ожидать. Ноstrxyz
семейство функций подходит довольно близко, когда вы знаете, что делаете. Смотрите C FAQ по строкам и массивам .источник