строки с фиксированной шириной и строки с нулевым окончанием - PullRequest
3 голосов
/ 22 мая 2010

gcc 4.4.4 c89

Я недавно вступил в дискуссию о "строках с фиксированной шириной" и "строках с нулевым окончанием".

Когда я думаю об этом. Кажется, они одно и то же. Строка с завершающим нулем.

т.е.

char *name = "Joe bloggs";

Строка фиксированной ширины, которую нельзя изменить. А также имеет завершающий ноль.

Также в обсуждении мне сказали, что strncpy никогда не следует использовать для «строк с нулевым окончанием».

Большое спасибо за любые предположения,

Ответы [ 3 ]

7 голосов
/ 22 мая 2010

Термин «строка фиксированной ширины» обычно относится к чему-то совершенно другому.

Строка фиксированной ширины с N - это строка из ровно N символов, где все символы N гарантированно инициализируются.Если вы хотите представить более короткую строку, вы должны дополнить ее нулевыми символами в конце.Вы должны добавить столько нулевых символов, сколько необходимо, чтобы использовать все символы N.Обратите внимание, что если вам нужно сохранить строку длины точно N, строка фиксированной ширины будет иметь без нулевого символа в конце.Т.е. в общем случае строки фиксированной ширины не завершаются нулями!

Какова цель этого?Цель этого - сохранить 1 символ при сохранении строки максимально возможной длины.Если вы используете строки фиксированной ширины шириной N, то вам нужно ровно N символов для представления строки длиной N.Сравните это с обычными строками с нулевым символом в конце, для которых потребуется символ N + 1 (дополнительный символ для терминатора нуля).

Почему в конце он дополняется нулями?Он дополняется нулями для упрощения лексикографического сравнения строк фиксированной ширины.Вы просто сравниваете все N символов, пока не достигнете разницы.Обратите внимание, что можно использовать абсолютно любой символ для дополнения строки фиксированной ширины до полной длины.Просто убедитесь, что вы получаете правильный лексикографический порядок.Использование нулевого символа для заполнения - хороший выбор.

Когда это полезно?Очень редко.Экономия, обеспечиваемая строками фиксированной ширины, редко важна при обработке общих строк: они слишком малы и происходят только в тех случаях, когда строка использует всю ширину.Но они могут пригодиться в некоторых конкретных случаях.

Откуда все это?Классическим примером «строки фиксированной ширины» является поле имени файла шириной 14 символов в какой-то старой версии файловой системы Unix.Он был представлен массивом из 14 символов, и было использовано представление с фиксированной шириной.В то время было важно сохранить 1 символ в имени файла полной длины (все 14 символов).

Теперь strncpy.Функция strncpy была специально введена для инициализации этих 14-символьных полей имени файла в этой файловой системе.Функция strncpy была специально создана для генерации правильной строки фиксированной ширины: она выполняет преобразование строки с нулевым окончанием в строку фиксированной ширины.К сожалению, ему было дано вводящее в заблуждение имя, поэтому многие люди сегодня принимают его за «безопасную» функцию копирования строк с нулевым символом в конце.Последнее является совершенно неверным пониманием цели и функциональности strncpy.

Использование строковых литералов для представления строк фиксированной ширины (как в вашем примере) не очень хорошая идея, поскольку строковые литералы всегда добавляют нулевой символв конце строки фиксированной ширины не обязательно делают это.Вот как набор строк фиксированной ширины может быть инициализирован в программе на Си

char fw_string1[7] = { 'T', 'h', 'i', 's', ' ', 'i', 's' };
char fw_string2[7] = { 's', 't', 'r', 'i', 'n', 'g' };
char fw_string3[7] = { 'H', 'e', 'l', 'l', 'o' };

Все массивы имеют одинаковое количество элементов - 7. Обратите внимание, что первая строка не заканчивается на ноль, аостальные заполнены нулями.Преобразование «обычной» строки в строку фиксированной ширины будет выглядеть следующим образом:

char fw_string4[7];

strncpy(fw_string4, "Hi!", 7);

В этом случае функция strncpy используется именно для того, для чего она предназначена.

Помните также, что кроме функции преобразования strncpy стандартная библиотека практически не предоставляет средств для работы со строками фиксированной ширины.В основном вы должны рассматривать их как необработанные массивы символов и выполнять любые операции более высокого уровня вручную.Большинство основных операций будут естественным образом реализованы функциями из группы mem....memcmp, для одного примера, осуществит сравнение.

P.S. На самом деле, принимая во внимание комментарий caf, в языке C можно использовать строковые литералы для инициализации строк фиксированной ширины, поскольку язык C позволяет инициализатору литерала быть на один символ длиннее массива (т.е. в C это нормально, если завершающий ноль делает не вписывается в массив). Таким образом, вышесказанное можно эквивалентно переписать как

char fw_string1[7] = "This is";
char fw_string2[7] = "string";
char fw_string3[7] = "Hello";

Обратите внимание, что в этом случае fw_string1 по-прежнему не заканчивается на ноль.

1 голос
/ 22 мая 2010

Я не совсем уверен насчет термина "строка фиксированной ширины". В зависимости от функции C строки нуждаются или не нуждаются в окончании \ 0. Такие функции, как strlen и strcpy должны работать с \ 0 завершенными строками, чтобы знать, когда следует остановиться. Такие функции, как strncpy , не требуют, чтобы исходная строка заканчивалась на \ 0, так как один аргумент сообщает, сколько символов скопировать.

Когда вы объявляете имя так, как вы это делаете, содержимое того, на что указывает имя, сохраняется в постоянной памяти и не может быть изменено, однако вы можете использовать «имя» в функциях C, которые не изменяют содержимое, например. strlen (имя) или при использовании в качестве источника:

char mycopy[32];
strcpy( mycopy, name );
1 голос
/ 22 мая 2010

Прежде всего, я думаю, что вы имеете в виду строку фиксированной длины, не фиксированную строкой.

Во-вторых, вышеприведенное является строкой с нулевым символом в конце. Его нельзя менять из-за его определения в качестве литеральной константы.

AFAIK C не имеет реальных "строк фиксированной длины". В лучшем случае вы можете определить буфер размером N и поместить в него не более N-1 символов, где размещение больше будет ошибкой, а забывание нулевого терминатора может быть ошибкой.

Что касается strncpy, то он делает то, что он копирует указанное количество символов, а остальные нули дополняют нулями. Это означает, что если место назначения недостаточно длинное, вы либо будете писать за пределами доступного пространства, либо не будете иметь нулевой терминатор для вашей строки, что приведет к ошибкам при попытке использовать строку.

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