Насколько я люблю C и С++, я не могу не почесать голову при выборе нулевых завершенных строк:
- Строки длиной до префикса (т.е. Паскаль) существовали до C
- Длина префиксных строк делает несколько алгоритмов быстрее, обеспечивая постоянный поиск длины.
- Длина префиксных строк делает сложнее вызвать ошибки переполнения буфера.
- Даже на 32-битной машине, если вы разрешаете строке быть размером доступной памяти, длина префиксной строки всего на три байта шире, чем строка с нулевым завершением. На 16-битных машинах это один байт. На 64-битных машинах 4 ГБ является разумным пределом длины строки, но даже если вы хотите расширить его до размера машинного слова, 64-разрядные машины обычно имеют достаточную память, что делает лишние семь байтов вроде нулевого аргумента. Я знаю, что оригинальный C-стандарт был написан для безумно бедных машин (с точки зрения памяти), но аргумент эффективности не продает меня здесь.
- Практически любой другой язык (например, Perl, Pascal, Python, Java, С# и т.д.) использует префиксные строки длины. Эти языки обычно били C в тестах обработки строк, потому что они более эффективны со строками.
- С++ исправил это немного с помощью шаблона
std::basic_string
, но простые массивы символов, ожидающие нулевых завершенных строк, все еще распространены. Это также несовершенно, потому что для этого требуется выделение кучи. - Строки с нулевым завершением должны зарезервировать символ (а именно, null), который не может существовать в строке, а строки с префиксом длины могут содержать внедренные нули.
Некоторые из этих вещей появились совсем недавно, чем C, поэтому было бы полезно, чтобы C не знал о них. Тем не менее, некоторые из них были хорошо известны до того, как C стал. Почему были выбраны нулевые завершенные строки вместо префикса явно превосходящей длины?
РЕДАКТИРОВАТЬ: поскольку некоторые из вас попросили факты (и мне не понравились те, которые я уже предоставил) по моей эффективности выше, они вытекают из нескольких вещей:
- Конкат, использующий нуль-завершенные строки, требует O (n + m) временной сложности. Для префикса длины часто требуется только O (m).
- Длина с использованием нулевых завершенных строк требует O (n) временной сложности. Префикс длины - O (1).
- Длина и concat являются наиболее распространенными строковыми операциями. Существует несколько случаев, когда нулевые завершаемые строки могут быть более эффективными, но они встречаются гораздо реже.
Из приведенных ниже ответов, это некоторые случаи, когда строки с нулевым завершением являются более эффективными:
- Когда вам нужно отключить начало строки и передать ее некоторому методу. Вы не можете сделать это в постоянное время с префиксом длины, даже если вам разрешено уничтожить исходную строку, потому что префикс длины, вероятно, должен следовать правилам выравнивания.
- В некоторых случаях, когда вы просто перебираете символ строки по символу, вы можете сохранить регистр CPU. Обратите внимание, что это работает только в том случае, если вы не динамически выделили строку (потому что тогда вам придется освободить ее, что потребовало бы использовать этот регистр процессора, который вы сохранили, чтобы удерживать указатель, который вы изначально получили от malloc и друзей).
Ни один из вышеперечисленных не является столь же общим, как длина и concat.
В ответах ниже сказано следующее:
- Вам нужно отрезать конец строки
но это неверно - это такое же количество времени для строк с нулевым завершением и длиной префикса. (Строки с нулевым завершающим строком просто вставляют нуль, где вы хотите, чтобы новый конец был, префиксы длины просто вычитают из префикса.)