Почему завершенные пустым указателем строки? Или: завершенный пустым указателем по сравнению с символами + устройство хранения данных длины

Вы можете сделать это следующим образом:

head, tail = os.path.split(url)

Если хвост будет вашим именем файла.

29
задан Pete Kirkham 20 August 2009 в 15:51
поделиться

10 ответов

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

Строки с завершающим нулем часто снижают производительность по той очевидной причине, что время, необходимое для определения длины, зависит от длины . С другой стороны, это стандартный способ представления строк в C, поэтому у вас мало выбора, кроме как поддерживать их, если вы хотите использовать большинство библиотек C.

17
ответ дан 28 November 2019 в 01:01
поделиться

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

7
ответ дан sharptooth 14 October 2019 в 07:18
поделиться

Немного оффтоп, но есть более эффективный способ создания строк с префиксом длины, чем тот, который вы описываете. Создайте структуру наподобие этой (действительной в C99 и выше):

struct String 
{
  size_t length;
  char characters[0];
}

Это создает структуру, которая имеет длину в начале, с элементом 'characters', используемым как char *, так же, как с ваша текущая структура. Разница, однако, заключается в том, что для каждой строки можно выделить только один элемент в куче вместо двух. Распределите ваши строки следующим образом:

mystr = malloc(sizeof(String) + strlen(cstring))

Например, длина структуры (которая является просто size_t) плюс достаточно места, чтобы поставить после нее фактическую строку.

Если вы не хотите использовать C99, вы также можете сделать это с помощью «символов символов [1]» и вычесть 1 из длины строки для выделения.

5
ответ дан Nick Johnson 14 October 2019 в 07:18
поделиться

У длин тоже есть свои проблемы.

  • Длина занимает дополнительную память (не такая проблема сейчас, но большой фактор 30 лет назад).

  • Каждый раз, когда вы изменяете строку, вы должны обновлять длину, чтобы снизить производительность по всем направлениям.

  • С NUL-оканчивающейся строкой вы все равно можете использовать длину или сохранять указатель на последний символ, поэтому, если вы делаете много строковых манипуляций, вы все равно можете равняться производительности строки с длиной.

  • NUL-концевые строки намного проще - NUL-терминатор - это просто соглашение, используемое такими методами, как strcat, для определения конца строки. Таким образом, вы можете хранить их в обычном массиве символов вместо использования структуры.

5
ответ дан Jason Williams 14 October 2019 в 07:18
поделиться

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

Мне понравилось, как Delphi хранит строки. Я считаю, что он поддерживает длину / максимальную длину перед строкой (переменной длины). Таким образом, строки могут заканчиваться нулем для совместимости.

Мои проблемы с вашим механизмом: - дополнительный указатель - неизменность si в основных частях вашего языка; обычно строковые типы не являются неизменяемыми, поэтому, если вы когда-нибудь пересмотрите их, это будет сложно. Вам необходимо реализовать механизм «создания копии при изменении» - использование malloc (вряд ли эффективно, но может быть включено сюда просто для удобства?)

Удачи; Написание собственного интерпретатора может быть очень познавательным в понимании в основном грамматики и синтаксиса языков программирования! (по крайней мере, это для меня)

1
ответ дан Adriaan 14 October 2019 в 07:18
поделиться

Из книги Джоэла Назад к основам :

Почему строки C работают именно так? Это потому, что микропроцессор PDP-7, на котором были изобретены UNIX и язык программирования C, имел строковый тип ASCIZ. ASCIZ означало «ASCII с Z (нулем) в конце».

Это единственный способ хранить строки? Нет, на самом деле, это один из худших способов хранения строк. Для нетривиальных программ, API, операционных систем, библиотек классов, вам следует избегать строк ASCIZ как чумы.

30
ответ дан 28 November 2019 в 01:01
поделиться

Одним из преимуществ строк с завершающим нулем является то, что если вы при просмотре строки посимвольно вам нужно сохранить только один указатель для адресации строки:

while (*s)
{
    *s = toupper(*s);
    s++;
}

, тогда как для строк без часовых вам нужно сохранить два бита состояния: либо указатель, либо индекс:

while (i < s.length)
{
    s.data[i] = toupper(s.data[i]);
    i++;
}

] ... или текущий указатель и ограничение:

s_end = s + length;
while (s < s_end)
{
    *s = toupper(*s);
    s++;
}

Когда регистры ЦП были дефицитным ресурсом (а компиляторы хуже выделяли их), это было важно. Теперь не так много.

вам нужно сохранить только один указатель для адресации строки:

while (*s)
{
    *s = toupper(*s);
    s++;
}

, тогда как для строк без часовых вам необходимо сохранить два бита состояния: либо указатель и индекс:

while (i < s.length)
{
    s.data[i] = toupper(s.data[i]);
    i++;
}

... или текущий указатель и limit:

s_end = s + length;
while (s < s_end)
{
    *s = toupper(*s);
    s++;
}

Когда регистры ЦП были дефицитным ресурсом (а компиляторы хуже выделяли их), это было важно. Теперь не так много.

вам нужно сохранить только один указатель для адресации строки:

while (*s)
{
    *s = toupper(*s);
    s++;
}

, тогда как для строк без часовых вам необходимо сохранить два бита состояния: либо указатель и индекс:

while (i < s.length)
{
    s.data[i] = toupper(s.data[i]);
    i++;
}

... или текущий указатель и limit:

s_end = s + length;
while (s < s_end)
{
    *s = toupper(*s);
    s++;
}

Когда регистры ЦП были дефицитным ресурсом (а компиляторы хуже выделяли их), это было важно. Теперь не так много.

6
ответ дан 28 November 2019 в 01:01
поделиться

Просто отбросим некоторые гипотезы:

  • нет способа получить "неправильную" реализацию строк с завершающим нулем. Однако стандартизованная структура может иметь реализации, зависящие от поставщика.
  • Никаких структур не требуется. Строки с завершающим нулем являются «встроенными», так сказать, в силу того, что они являются частным случаем char *.
4
ответ дан 28 November 2019 в 01:01
поделиться

Хотя в большинстве случаев я предпочитаю метод array + len, есть веские причины для использования завершающего нуля.

Возьмем 32-битную систему.

Чтобы сохранить 7-байтовую строка
char * + size_t + 8 байтов = 19 байтов

Для хранения 7-байтовой строки с нулевым термином
char * + 8 = 16.

массивы с нулевым членом не обязательно должны быть неизменяемыми, как это делают ваши строки. Я могу с радостью обрезать c-строку, просто поместив нулевой символ. Если вы пишете код, вам нужно будет создать новую строку, которая включает выделение памяти.

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

1
ответ дан 28 November 2019 в 01:01
поделиться

Я думаю, что основная причина в том, что в стандарте ничего конкретного не говорится о размере любого типа, кроме char. Но sizeof (char) = 1, и этого явно недостаточно для размера строки.

0
ответ дан 28 November 2019 в 01:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: