web-dev-qa-db-fra.com

Comment calculer la longueur d'une chaîne en C efficacement?

Comment calculer la longueur d'une chaîne en C efficacement (dans le temps)?

En ce moment je fais:

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

Mais c'est très lent comparé à strlen () par exemple, y a-t-il un autre moyen de le faire?

Merci.

EDIT: Je travaille dans un environnement indépendant, je ne suis pas autorisé à utiliser une bibliothèque externe, y compris "string.h".

20
Carla Álvarez

À partir du code source de FreeBSD :

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

Comparé à votre code, cela correspond probablement très bien à une instruction d'assembleur, ce qui peut expliquer une grande différence de performances.

40
Andomar

Regardez le code source de strlen dans la libc standard. Les fonctions des bibliothèques standard sont généralement hautement optimisées. Vérifiez-le ici (codé dans Assembly) - cela provient de la 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;
}
9
Sudhanshu

strlen(). Si quelqu'un avait trouvé une méthode générique plus rapide et de meilleure qualité, il aurait été remplacé par strlen.

9
aib

Jetez un coup d’œil à la source strlen() de la bibliothèque GNU C

Il utilise plusieurs astuces non évidentes pour gagner de la vitesse sans passer à Assembly, notamment:

  • arriver à un personnage qui est correctement aligné
  • lire ces parties alignées de la chaîne dans un int (ou un type de données plus grand) pour lire plusieurs caractères à la fois
  • en utilisant des astuces pour vérifier si l'un des caractères incorporés dans ce bloc est nul

etc.

6
Michael Burr

Le moyen le plus simple est d’appeler strlen(). Sérieusement. Il est déjà optimisé par vos fournisseurs de compilateur et/ou de bibliothèque pour être aussi rapide que possible pour votre architecture.

Une optimisation courante consiste à supprimer le besoin d'augmenter un compteur et à calculer la longueur à partir du pointeur:

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

  while(*s)
   s++;

  return s - anchor;
}
3
unwind

Les chaînes de caractères C sont intrinsèquement inefficaces , il y a deux raisons d'utiliser la convention ASCIZ:

  • La bibliothèque standard C l'utilise
  • Le compilateur l'utilise pour les constantes littérales

Le premier d'entre eux est académique dans ce cas puisque vous n'utilisez pas la bibliothèque standard, le second est facilement surmonté en créant des fonctions ou des macros qui fournissent des conversions de chaînes C en une convention plus efficace telle que les chaînes Pascal. Le fait est que vous n'êtes pas obligé d'être esclave de la convention C si vous n'utilisez pas la bibliothèque C.

3
Clifford

Une autre façon d'accélérer le comptage des caractères est d'utiliser la vectorisation!

Voici un exemple de procédure à suivre pour les chaînes codées en UTF8:

Comptage encore plus rapide des caractères UTF-8,

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

2
qbitty

Certaines des réponses ci-dessus sont très bonnes, et c’est ce que je retiens . Il existe un mot clé appelé "register"

#include <stdio.h>
size_t strlenNew(char *s);

int main(int argc, char* argv[])
{
    printf("Size of \"Hello World\" is ::\t%d",strlenNew("Hello World"));
    return 0;
}

size_t strlenNew(char *s)
{
    register int i=0;
    while(s[i]!='\0') i++;
    return i;
}

Lire ici: http://gustedt.wordpress.com/2010/08/17/a-common-misconsception-the-register-keyword/ et http://msdn.Microsoft.com/en- us/bibliothèque/482s4fy9 (v = vs.80) .aspx

Du premier lien:

Cela peut être particulièrement utile pour les variables de tableau. Une variable de tableau est facilement confondu avec une variable de pointeur. À moins que cela soit suivi de un [expr] ou avec un sizeof il évalue à l'adresse du premier élément. Si vous déclarez le tableau, toutes ces utilisations sont interdit; nous accédons seulement aux éléments individuels ou demandons le total Taille. Un tel tableau de registres est alors beaucoup plus simple à utiliser comme s'il s'agissait de étaient juste un ensemble de variables par l'optimiseur. Aucun aliasing (accès à la même variable par différents pointeurs) ne peut se produire.

Ainsi, il peut parfois y avoir des fluctuations de performances. Personnellement, ceci est une de mes implémentations fav, mais Sudhanshu et Andomar fournissent également une bonne implémentation :)

0

J'ai eu le même problème et je l'ai résolu. La clé est la 2ème condition de la boucle 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;
}
0
Victor26567

Programme C de base pour calculer la longueur de la chaîne.

#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;
}

NOTE: Pour une meilleure solution, nous devrions toujours laisser passer la taille de la matrice pour éviter les fuites de mémoire. Par exemple, le prototype de la méthode devrait être *: *

/**
* @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
Rahul Raina

Je n'ai pas trouvé mieux:

en ligne size_t mystrlen (char * _)

  { return ((_ == NULL) ? (_[0] != '\0')) ? 0 : (1 + mystrlen(_ + 1)); }
0
blueperfect

Sur les processeurs i386, la libc utilise souvent une version ultra-optimisée de strlen, souvent écrite en langage Assembly. Le document " String Length " explique leur fonctionnement.

Voici une version optimisée pour OpenBSD . (Ils ont aussi une version portable .) Voici la version pour le GNU libc .

0
bortzmeyer