Как рассчитать длину строки в C эффективно? - PullRequest
20 голосов
/ 15 января 2010

Как рассчитать длину строки в C эффективно (по времени)?

Прямо сейчас я делаю:

int calculate_length(char *string) {
    int length = 0;
    while (string[length] != '\0') {
        length++;
    }
    return length;
}

Но это очень медленно по сравнению с strlen (), например, есть ли другой способ сделать это?

Спасибо.

РЕДАКТИРОВАТЬ: я работаю в автономной среде, мне не разрешено использовать какие-либо внешние библиотеки, включая "string.h".

Ответы [ 14 ]

41 голосов
/ 15 января 2010

Из исходного кода FreeBSD :

size_t
strlen(const char *str)
{
    const char *s;
    for (s = str; *s; ++s);
    return(s - str);
}

По сравнению с вашим кодом, это, вероятно, очень хорошо отображает инструкцию ассемблера, которая может объяснить большую разницу в производительности.

9 голосов
/ 15 января 2010

strlen(). Скорее всего, если бы кто-то нашел лучший, более быстрый универсальный метод, strlen был бы заменен этим.

9 голосов
/ 15 января 2010

Посмотрите на исходный код strlen в стандартном libc. Функции в стандартных библиотеках, как правило, сильно оптимизированы. Проверьте это здесь (закодировано в сборке) - это из GNU libc.

size_t
DEFUN(strlen, (str), CONST char *str)
{
  int cnt;

  asm("cld\n"                   /* Search forward.  */
      /* Some old versions of gas need `repne' instead of `repnz'.  */
      "repnz\n"                 /* Look for a zero byte.  */
      "scasb" /* %0, %1, %3 */ :
      "=c" (cnt) : "D" (str), "0" (-1), "a" (0));

  return -2 - cnt;
}
6 голосов
/ 15 января 2010

Взгляните на GNU C библиотеки strlen() source .

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

  • добраться до персонажа, который правильно выровнен
  • чтение этих выровненных частей строки в int (или некоторый больший тип данных) для чтения нескольких символов за раз
  • использование трюков с битами, чтобы проверить, равен ли один из символов, встроенных в этот блок символов, нулю

и т.д.

3 голосов
/ 15 января 2010

C строк по сути неэффективны , есть две причины для использования соглашения ASCIZ:

  • Стандартная библиотека C использует его
  • Компилятор использует его для строковых констант

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

3 голосов
/ 15 января 2010

Самый простой способ - позвонить strlen(). Шутки в сторону. Он уже оптимизирован вашим компилятором и / или поставщиками библиотек, чтобы быть максимально быстрым для вашей архитектуры.

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

size_t my_strlen(const char *s)
{
  const char *anchor = s;

  while(*s)
   s++;

  return s - anchor;
}
2 голосов
/ 15 января 2010

Еще один способ ускорить подсчет символов - использовать векторизацию!

Вот пример того, как это сделать в отношении строк в кодировке UTF8:

Еще более быстрый подсчет символов UTF-8,

http://www.daemonology.net/blog/2008-06-05-faster-utf8-strlen.html

0 голосов
/ 20 сентября 2017

Базовая программа C для расчета длины строки.

#include <stdio.h>

/**
* Method to calculate string length.
* Returns -1 in case of null pointer, else return string length.
**/
int length(char *str) {

    int i = -1;
    // Check for NULL pointer, then return i = -1;
    if(str == NULL) return i;

    // Iterate till the empty character.
    while (str[++i] != '\0');
    return i;  // Return string length.
}

int main (int argc, char **argv) {

    int len = 0;
    char abc[] = "hello";
    len = length(abc);
    printf("%d", len);  
    return 0;
}

ПРИМЕЧАНИЕ. Для лучшего способа мы всегда должны передавать размер массива, чтобы избежать утечки памяти. Например, ** прототип метода должен быть *: *

/**
* @desc calculate the length of str.
* @param1 *str pointer to base address of char array.
* @param2 size = capacity of str to hold characters.
* @return int -1 in case of NULL, else return string length.
**/
int length (char *str, int size);
0 голосов
/ 24 сентября 2016

лучше не нашел:

встроенный size_t mystrlen (char * _)

  { return ((_ == NULL) ? (_[0] != '\0')) ? 0 : (1 + mystrlen(_ + 1)); }
0 голосов
/ 30 августа 2016

У меня была такая же проблема, и я решил ее.Ключ является вторым условием цикла for:

int longitud(char cad[]){

    int i, cont;

    cont = 0;

    for(i = 0; i < 30 && cad[i] != '\0'; i++){
        if(cad[i] != '\0'){
            if(cad[i] != ' '){
                cont++;
            }
        }
    }
    cont--;
    return cont;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...