Наскільки я люблю C і C ++, я не можу не почухати голову при виборі нульових завершених рядків:
- Попередньо встановлені (тобто Pascal) рядки існували до C
- Префіксні рядки по довжині роблять кілька алгоритмів швидшими, дозволяючи шукати постійну тривалість часу.
- Попередньо встановлені рядки по довжині ускладнюють помилки перевиконання буфера.
- Навіть на 32-бітовій машині, якщо ви дозволяєте рядку мати розмір доступної пам'яті, строка з попередньою фіксованою довжиною лише на три байти ширше, ніж нульовий завершений рядок. На 16-бітних машинах це один байт. На 64-бітних машинах 4 Гб є розумним обмеженням довжини рядків, але навіть якщо ви хочете розширити його до розміру машинного слова, 64-бітні машини, як правило, мають достатньо пам'яті, роблячи додаткові сім байтів на зразок нульового аргументу. Я знаю, що оригінальний стандарт C був написаний для шалено бідних машин (з точки зору пам'яті), але аргумент ефективності мене тут не продає.
- Практично будь-яка інша мова (наприклад, Perl, Pascal, Python, Java, C # тощо) використовує рядки з попередньою приставкою. Ці мови, як правило, б'ють С у орієнтирах маніпулювання рядками, оскільки вони ефективніші за допомогою рядків.
- C ++ дещо виправив це за допомогою
std::basic_string
шаблону, але масиви простих символів, які очікують, що нульові завершені рядки все ще поширені. Це також недосконало, оскільки воно вимагає виділення купи. - Нульові завершені рядки повинні резервувати символ (а саме - null), який не може існувати в рядку, тоді як рядки з попередньою приставкою по довжині можуть містити вбудовані нулі.
Деякі з цих речей з’явилися на світ останнім часом, ніж C, тому для С було б сенс не знати про них. Однак декілька були очевидними задовго до появи С. Чому замість очевидно переважних префіксів довжини було обрано нульові закінчені рядки?
EDIT : Оскільки деякі запитували факти (і не сподобалися ті, які я вже надав) щодо моєї точки зору ефективності, вони випливають із кількох речей:
- Concat з використанням нульових кінцевих рядків вимагає складності часу O (n + m). Префіксація по довжині часто вимагає лише O (м).
- Довжина з використанням нульових кінцевих рядків вимагає O (n) часової складності. Префіксація довжини - O (1).
- Довжина та лаконічність - на сьогоднішній день найбільш поширені струнні операції. Є кілька випадків, коли нульові завершені рядки можуть бути більш ефективними, але вони трапляються набагато рідше.
З наведених нижче відповідей, це деякі випадки, коли нульові завершені рядки є більш ефективними:
- Коли потрібно відрізати початок рядка і потрібно передати його якомусь методу. Ви дійсно не можете це робити в постійний час з префіксом довжини, навіть якщо вам дозволяється знищити початковий рядок, оскільки, префікс довжини, ймовірно, повинен дотримуватися правил вирівнювання.
- У деяких випадках, коли ви просто перебираєте символи рядка за символом, можливо, ви зможете зберегти регістр процесора. Зауважте, що це працює лише у випадку, якщо ви не динамічно виділили рядок (Тому що тоді вам доведеться звільнити її, вимагаючи використання цього реєстру CPU, який ви зберегли, щоб утримувати покажчик, який ви спочатку отримали від malloc та друзів).
Жодне з перерахованого вище майже не таке поширене, як довжина і лаконічність.
У відповідях нижче є ще один твердження:
- Потрібно відрізати кінець рядка
але це невірно - це стільки ж часу для нульових завершених і довжиною префіксів рядків. (Строкові завершені рядки просто приклеюють нуль там, де ви хочете, щоб був новий кінець, префіксатори довжини просто віднімають від префікса.)