Почему строки в C должны заканчиваться нулем?
Просто интересно, почему это так. Мне не терпится узнать больше о языках низкого уровня, и я разбираюсь только в основах C, и это уже сбивает меня с толку.
Языки, такие как PHP, автоматически обнуляют строки, когда они интерпретируются и / или анализируются?
9 ответов
Из отличной статьи Джоэла на эту тему:
Вспомните, как работают строки в C: они состоят из группы байтов, за которыми следует нулевой символ, значение которого равно 0. Это имеет два очевидных значения:
Невозможно узнать, где заканчивается строка (то есть длина строки), не перемещаясь по ней, ища нулевой символ в конце. В вашей строке не должно быть нулей. Таким образом, вы не можете хранить произвольный двоичный объект типа картинки JPEG в строке C. Почему строки C работают таким образом? Это потому, что микропроцессор PDP-7, на котором были изобретены UNIX и язык программирования C, имел строковый тип ASCIZ. ASCIZ означает "ASCII с Z (ноль) в конце".
Это единственный способ хранить строки? Нет, на самом деле, это один из худших способов хранения строк. Для нетривиальных программ, API, операционных систем, библиотек классов следует избегать строк ASCIZ, таких как чума.
Подумайте, что такое память: непрерывный блок блоков размером в байт, который может быть заполнен любыми битовыми комбинациями.
2a c6 90 f6
Персонаж - это просто одна из тех битовых комбинаций. Его значение как строки определяется тем, как вы к нему относитесь. Если вы посмотрели на ту же часть памяти, но с использованием целочисленного представления (или другого типа), вы получите другое значение.
Если у вас есть переменная, которая является указателем на начало группы символов в памяти, вы должны знать, когда эта строка заканчивается и начинается следующий фрагмент данных (или мусор).
пример
Давайте посмотрим на эту строку в памяти...
H e l l o , w o r l d ! \0
^
|
+------ Pointer to string
... мы видим, что строка логически заканчивается после !
персонаж. Если бы не было \0
(или любой другой метод определения его конца), как мы узнаем, ища в памяти, что мы закончили с этой строкой? Другие языки содержат длину строки с типом строки, чтобы решить эту проблему.
Я задал этот вопрос, когда мои базовые знания о компьютерах были ограничены, и этот ответ помог бы много лет назад. Я надеюсь, что это помогает кому-то еще.:)
Строки C - это массивы символов, а массив C - это просто указатель на область памяти, которая является начальной точкой массива. Но также длина (или конец) массива должна быть выражена как-то; в случае строк используется нулевое окончание. Другой альтернативой может быть как-то перенести длину строки вместе с указателем памяти, или поместить длину в первое место массива, или что-то еще. Это просто вопрос соглашения.
Языки более высокого уровня, такие как Java или PHP, хранят информацию о размере в массиве автоматически и прозрачно, поэтому пользователю не нужно беспокоиться о них.
С не имеет понятия о строках. Строки - это просто массивы символов (или wchars для юникода и тому подобное).
Из-за этих фактов C не может проверить, то есть длину строки, так как нет "mystring->length", где-то не установлено значение длины. Единственный способ найти конец строки - это перебрать ее и проверить наличие \0.
Есть строковые библиотеки для C, которые используют такие структуры, как
struct string {
int length;
char *data;
};
убрать необходимость в \0-завершении, но это не стандартная C.
Такие языки, как C++, PHP, Perl и т. Д., Имеют свои собственные внутренние строковые библиотеки, которые часто имеют отдельное поле длины, которое ускоряет некоторые строковые функции и устраняет необходимость в \0.
Некоторые другие языки (например, Pascal) используют строковый тип, который называется (удивительно) Pascal String, он хранит длину в первом байте строки, что является причиной того, что длина этих строк ограничена 255 символами.
Потому что в C строки представляют собой просто последовательность символов, доступ к которым осуществляется через указатель на первый символ.
В указателе нет места для хранения длины, поэтому вам нужно указать, где находится конец строки.
В Си было решено, что это будет обозначено нулевым символом.
Например, в паскале длина строки записывается в байте, непосредственно предшествующем указателю, поэтому максимальная длина строки паскаля составляет 255 символов.
В C строки представлены массивом символов, размещенных в непрерывном блоке памяти, и, таким образом, должен быть либо индикатор, указывающий конец блока (т. Е. Нулевой символ), либо способ хранения длины (например, строки Pascal). которые начинаются с длины).
В таких языках, как PHP,Perl,C# и т. Д. Строки могут иметь или не иметь сложные структуры данных, поэтому нельзя предполагать, что они имеют нулевой символ. В качестве надуманного примера у вас может быть язык, который представляет строку примерно так:
class string
{
int length;
char[] data;
}
но вы видите ее только как обычную строку без поля длины, так как она может быть рассчитана средой выполнения языка и используется только для внутреннего использования для правильного распределения и доступа к памяти.
Это соглашение - его можно было бы реализовать с помощью другого алгоритма (например, длина в начале буфера).
На "низкоуровневом" языке, таком как ассемблер, легко эффективно проверить на "NULL": это может упростить решение использовать строки с завершающими NULL, а не отслеживать счетчик длины.
Они должны быть завершены нулем, чтобы вы знали, как долго они. И да, они просто массивы char.
Языки более высокого уровня, такие как PHP, могут скрывать нулевое завершение от вас или не использовать его вообще - например, они могут поддерживать длину. C не делает это таким образом из-за накладных расходов. Языки высокого уровня могут также не реализовывать строки в виде массива char - они могут (а некоторые и делают) реализовывать их в виде списков массивов char, например.
Они заканчиваются нулем, потому что все функции стандартной библиотеки ожидают их.