Какова лучшая альтернатива вызову strlen () в цикле my for в C? - PullRequest
4 голосов
/ 03 марта 2010

Я читал, что это плохая практика - вызывать strlen () в моем цикле for, потому что это операция O (N).

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

int len = strlen(somestring);  
for(int i = 0; i < len; i++)  
{

}

или ...

for(int i = 0; somestring[i] != '\0'; i++)  
{

}

Теперь, второй вариант выглядит так, как будто он имеет преимущество: 1) не объявлять ненужную переменную, и 2) если длина строки изменяется в цикле, она все равно должна достигать конца, пока длина не <я. </p>

Однако я не уверен. Какой из них является стандартной практикой среди программистов на Си?

Ответы [ 6 ]

9 голосов
/ 03 марта 2010

Второй, как правило, предпочтительнее.

Другая популярная форма

for (char* p = something; *p; p++)
{
   // ... work with *p
}

Еще один

char* p = something;
char c;
while ((c = *p++))
{
    // ... do something with c
}

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

Действительно, strlen довольно медленный, потому что он должен пройти всю строку в поисках завершающего 0. Итак, strlen по существу реализован как

int s = 0;
while (*p++) s++;
return s;

(на самом деле используется немного более оптимизированная версия на ассемблере).

Так что вам следует избегать использования strlen, если это возможно.

3 голосов
/ 03 марта 2010

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

3 голосов
/ 03 марта 2010

Это предпочтительные:

for (int i = 0; str[i]; ++i)
for (char* p = str; *p; ++p)
1 голос
/ 03 марта 2010

Обычно второй. Если ничего другого, первый должен пройти строку дважды: один раз, чтобы найти длину, и снова, чтобы воздействовать на каждый элемент. С другой стороны, если у вас уже написан код strlen, может быть проще просто вывести вызов strlen из цикла и при этом получить большинство выгоды.

0 голосов
/ 31 августа 2011

Как указали другие ответы, в то время как оба варианта работают, второй является более обычным. Но я не рекомендую сравнивать символы с \ 0. Тип '\ 0' - это int, а не char. Таким образом, он имеет тот же тип, что и 0. Однако, он более подвержен ошибкам при записи «\ 0», чем просто 0, потому что случайный возврат может преобразовать его в «0», что вовсе не то же самое. Этот баг не может быть легко обнаружен кем-то, кто случайно читает код.

0 голосов
/ 03 марта 2010

Первый подход для меня выглядит так:

while(..) { Test end of string }  /* strlen */
while(..) { Your Code }           /* processing */

Пока второй подход выглядит так:

while(..) { Your Code + Test end of string } /* both */

ИМХО, оба подхода вычисляют примерно одинаковое количество операций, и Я считаю их эквивалентными. Кроме того, strlen довольно оптимизирован , как уже упоминалось, и хорошо проверено. Более того, второй подход выглядит как преждевременная оптимизация :) Вы бы лучше при необходимости протестируйте / профилируйте свой код, а затем оптимизируйте (в конце концов, это только линейный алгоритм)

Однако вы можете рассмотреть второй подход, если обработка возможно, остановится задолго до конца строки (например, найти первое вхождение слова).

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