Je vais deviner que sans une optimisation sophistiquée capable de détecter que cela ne change jamais dans la boucle, alors oui. Il est préférable de compiler et de regarder l'assemblage pour voir.
MerickOWA
6
Cela dépend du compilateur, du niveau d'optimisation et de ce que vous (pourriez) faire à l' ssintérieur de la boucle.
Hristo Iliev
4
Si le compilateur peut prouver que ce ssn'est jamais modifié, il peut sortir le calcul de la boucle.
Daniel Fischer
10
@Mike: "nécessite une analyse à la compilation de ce que fait exactement strlen" - strlen est probablement un intrinsèque, auquel cas l'optimiseur sait ce qu'il fait.
Steve Jessop
3
@MikeSeymour: Il n'y a pas de peut-être, peut-être pas. strlen est défini par le standard du langage C, et son nom est réservé à l'usage défini par le langage, donc un programme n'est pas libre de fournir une définition différente. Le compilateur et l'optimiseur sont en droit de supposer que strlen dépend uniquement de son entrée et ne le modifie pas ni aucun état global. Le défi de l'optimisation ici est de déterminer que la mémoire pointée par ss n'est altérée par aucun code à l'intérieur de la boucle. C'est tout à fait faisable avec les compilateurs actuels, en fonction du code spécifique.
Eric Postpischil
Réponses:
138
Oui, strlen()sera évalué à chaque itération. Il est possible que, dans des circonstances idéales, l'optimiseur puisse en déduire que la valeur ne changera pas, mais je ne me fierais personnellement pas à cela.
Je ferais quelque chose comme
for(int i =0, n = strlen(ss); i < n;++i)
ou éventuellement
for(int i =0; ss[i];++i)
tant que la chaîne ne changera pas de longueur pendant l'itération. Si c'est le cas, vous devrez soit appeler à strlen()chaque fois, soit le gérer selon une logique plus compliquée.
Si vous savez que vous ne manipulez pas la chaîne, la seconde est bien plus préférable car c'est essentiellement la boucle qui sera exécutée de strlentoute façon.
mlibpar
26
@alk: Si la chaîne peut être raccourcie, alors les deux sont faux.
Mike Seymour
3
@alk: si vous changez la chaîne, une boucle for n'est probablement pas le meilleur moyen d'itérer sur chaque caractère. Je pense qu'une boucle while est plus directe et plus facile à gérer le compteur d'index.
mlibpar le
2
les circonstances idéales incluent la compilation avec GCC sous Linux, où strlenest marqué comme __attribute__((pure))permettant au compilateur d'élider plusieurs appels. Attributs GCC
David Rodríguez - dribeas
6
La deuxième version est la forme idéale et la plus idiomatique. Il vous permet de passer la chaîne une seule fois plutôt que deux, ce qui aura de bien meilleures performances (en particulier la cohérence du cache) pour les longues chaînes.
R .. GitHub STOP HELPING ICE
14
Oui, chaque fois que vous utilisez la boucle. Ensuite, il calculera à chaque fois la longueur de la chaîne. alors utilisez-le comme ceci:
char str[30];for(int i =0; str[i]!='\0'; i++){//Something;}
Dans le code ci-dessus str[i]ne vérifie qu'un caractère particulier dans la chaîne à l'emplacement ichaque fois que la boucle démarre un cycle, donc cela prendra moins de mémoire et sera plus efficace.
Dans le code ci-dessous, chaque fois que la boucle s'exécute strlen, la longueur de la chaîne entière sera comptée, ce qui est moins efficace, prend plus de temps et prend plus de mémoire.
char str[];for(int i =0; i < strlen(str); i++){//Something;}
Je suis d'accord avec "[c'est] plus efficace", mais utilise moins de mémoire? La seule différence d'utilisation de la mémoire à laquelle je peux penser serait dans la pile d'appels pendant l' strlenappel, et si vous êtes aussi serré, vous devriez probablement penser à éliminer quelques autres appels de fonction également ...
un CVn
@ MichaelKjörling Eh bien, si vous utilisez "strlen", alors dans une boucle, il doit parcourir toute la chaîne à chaque fois que la boucle s'exécute, alors que dans le code ci-dessus le "str [ix]", il ne scanne qu'un seul élément à chaque cycle du boucle dont l'emplacement est représenté par "ix". Ainsi, il faut moins de mémoire que "strlen".
codeDEXTER
1
Je ne suis pas sûr que cela ait beaucoup de sens, en fait. Une implémentation très naïve de strlen serait quelque chose commeint strlen(char *s) { int len = 0; while(s[len] != '\0') len++; return len; } qui est à peu près exactement ce que vous faites dans le code de votre réponse. Je ne dis pas qu'itérer sur la chaîne une fois plutôt que deux est plus efficace en temps , mais je ne vois pas l'un ou l'autre utilisant plus ou moins de mémoire. Ou faites-vous référence à la variable utilisée pour contenir la longueur de la chaîne?
un CVn le
@ MichaelKjörling Veuillez consulter le code édité ci-dessus et le lien. Et en ce qui concerne la mémoire, chaque fois que la boucle s'exécute, chaque valeur itérée est stockée en mémoire et en cas de «strlen», car il compte la chaîne entière encore et encore, il nécessite plus de mémoire pour stocker. et aussi parce que contrairement à Java, C ++ n'a pas de "Garbage Collector". Alors je peux me tromper aussi. voir le lien concernant l'absence de "Garbage Collector" en C ++.
codeDEXTER
1
@ aashis2s L'absence de garbage collector ne joue un rôle que lors de la création d'objets sur le tas. Les objets sur la pile sont détruits dès que la portée et se termine.
Ikke
9
Un bon compilateur peut ne pas le calculer à chaque fois, mais je ne pense pas que vous puissiez être sûr que chaque compilateur le fait.
En plus de cela, le compilateur doit savoir que strlen(ss)cela ne change pas. Ceci n'est vrai que s'il ssn'est pas modifié en forboucle.
Par exemple, si vous utilisez une fonction en lecture seule sur ssdansfor loop mais que vous ne déclarez pas le ssparamètre -paramètre comme const, le compilateur ne peut même pas savoir que ce ssn'est pas changé dans la boucle et doit calculer strlen(ss)à chaque itération.
+1: Non seulement ne doit sspas être changé dans la forboucle; il ne doit pas être accessible depuis et modifié par une fonction appelée dans la boucle (soit parce qu'il est passé en argument, soit parce qu'il s'agit d'une variable globale ou d'une variable de portée fichier). La qualification des constants peut également être un facteur.
Jonathan Leffler
4
Je pense qu'il est hautement improbable que le compilateur sache que «ss» ne change pas. Il pourrait y avoir des pointeurs errants qui pointent vers la mémoire à l'intérieur de 'ss' dont le compilateur n'a aucune idée de qui pourraient changer 'ss'
MerickOWA
Jonathan a raison, une chaîne de const locale pourrait être le seul moyen pour le compilateur de s'assurer qu'il n'y a aucun moyen pour «s» de changer.
MerickOWA
2
@MerickOWA: en effet, c'est l'une des choses qui restrictest pour C99.
Steve Jessop
4
Concernant votre dernier para: si vous appelez une fonction en lecture seule ssdans la boucle for, alors même si son paramètre est déclaré const char*, le compilateur a encore besoin de recalculer la longueur à moins que (a) il sache que sspointe vers un objet const, au lieu d'être simplement un pointeur vers const, ou (b) il peut insérer la fonction ou voir autrement qu'elle est en lecture seule. Prendre un const char*paramètre n'est pas une promesse de ne pas modifier les données pointées, car il est valide de transtyper char*et de modifier à condition que l'objet modifié ne soit pas const et ne soit pas une chaîne littérale.
Steve Jessop
4
Si ssest de type const char *et que vous ne rejetez pas le constness dans la boucle, le compilateur ne peut appeler strlenqu'une seule fois, si les optimisations sont activées. Mais ce n'est certainement pas un comportement sur lequel on peut compter.
Vous devez enregistrer le strlenrésultat dans une variable et utiliser cette variable dans la boucle. Si vous ne souhaitez pas créer de variable supplémentaire, en fonction de ce que vous faites, vous pourrez peut-être vous en sortir en inversant la boucle pour itérer en arrière.
for(auto i = strlen(s); i >0;--i ){// do whatever// remember value of s[strlen(s)] is the terminating NULL character}
C'est une erreur d'appeler strlendu tout. Faites une boucle jusqu'à ce que vous atteigniez la fin.
R .. GitHub STOP HELPING ICE
i > 0? Cela ne devrait-il pas être i >= 0ici? Personnellement, je commencerais aussi par strlen(s) - 1itérer sur la chaîne à l'envers, alors la terminaison \0n'a pas besoin de considération particulière.
un CVn le
2
@ MichaelKjörling i >= 0ne fonctionne que si vous initialisez à strlen(s) - 1, mais si vous avez une chaîne de longueur nulle, la valeur initiale est inférieure
Prétorien
@ Prætorian, bon point sur la chaîne de longueur nulle. Je n'ai pas considéré ce cas lorsque j'ai écrit mon commentaire. C ++ évalue-t-il l' i > 0expression lors de l'entrée de boucle initiale? Si ce n'est pas le cas, alors vous avez raison, le cas de longueur nulle rompra définitivement la boucle. Si c'est le cas, vous obtenez "simplement" un signe i== -1 <0 donc pas d'entrée de boucle si le conditionnel est i >= 0.
un CVn du
@ MichaelKjörling Oui, la condition de sortie est évaluée avant d'exécuter la boucle pour la première fois. strlenLe type de retour de n'est pas signé, donc prend la valeur (strlen(s)-1) >= 0true pour les chaînes de longueur nulle.
Prétorien
3
Formellement oui, strlen()on s'attend à ce qu'il soit appelé à chaque itération.
Quoi qu'il en soit, je ne veux pas nier la possibilité de l'existence d'une optimisation intelligente du compilateur, qui optimisera tout appel successif à strlen () après le premier.
Le code du prédicat dans son intégralité sera exécuté à chaque itération de la forboucle. Afin de mémoriser le résultat de l' strlen(ss)appel, le compilateur aurait besoin de savoir qu'au moins
La fonction strlenétait sans effet secondaire
La mémoire pointée par ssne change pas pendant la durée de la boucle
Le compilateur ne sait ni l'une ni l'autre de ces choses et ne peut donc pas mémoriser en toute sécurité le résultat du premier appel
Eh bien, il pourrait savoir ces choses avec une analyse statique, mais je pense que votre point est que cette analyse n'est actuellement pas implémentée dans aucun compilateur C ++, oui?
GManNickG
@GManNickG cela pourrait certainement prouver le n ° 1 mais le n ° 2 est plus difficile. Pour un seul thread, oui, cela pourrait certainement le prouver, mais pas pour un environnement multi-thread.
JaredPar
1
Peut-être que je suis têtu, mais je pense que le numéro deux est également possible dans les environnements multithread, mais certainement pas sans un système d'inférence extrêmement puissant. Juste rêver ici cependant; définitivement au-delà de la portée de tout compilateur C ++ actuel.
GManNickG
@GManNickG Je ne pense pas que ce soit possible en C / C ++. Je pourrais très facilement cacher l'adresse de ssen un size_tou la diviser entre plusieurs bytevaleurs. Mon thread sournois pourrait alors simplement écrire des octets dans cette adresse et le compilateur aurait un moyen de comprendre à quoi il s'agissait ss.
JaredPar
1
@JaredPar: Désolé de cogner, vous pouvez prétendre que int a = 0; do_something(); printf("%d",a);cela ne peut pas être optimisé, car cela do_something()pourrait faire votre chose int non initialisée, ou pourrait remonter la pile et modifier adélibérément. En fait, gcc 4.5 l'optimise do_something(); printf("%d",0);avec -O3
Steve Jessop
2
Oui . strlen sera calculé à chaque fois que i augmente.
Si vous n'avez pas changé ss avec dans la boucle , cela n'affectera pas la logique, sinon cela affectera.
Il est plus sûr d'utiliser le code suivant.
int length = strlen(ss);for(int i =0; i < length ;++ i ){// blabla}
OUI, en termes simples. Et il y a un petit non dans une condition rare dans laquelle le compilateur le souhaite, comme étape d'optimisation s'il constate qu'il n'y a pas du tout de modifications apportées ss. Mais en bon état, vous devriez le penser comme OUI. Il y a des situations comme un programme in multithreadedet event, il peut devenir bogué si vous le considérez comme NON. Soyez prudent car cela n'améliorera pas trop la complexité du programme.
Je pense que faire cette modification particulière ne modifie jamais la longueur de ss, juste son contenu, donc (un compilateur vraiment, vraiment intelligent) pourrait encore optimiser strlen.
La condition de boucle est évaluée après chaque répétition, avant de redémarrer la boucle.
Faites également attention au type que vous utilisez pour gérer la longueur des chaînes. ce devrait être celui size_tqui a été défini comme unsigned intdans stdio. le comparer et le convertir intpeut causer de sérieux problèmes de vulnérabilité.
eh bien, j'ai remarqué que quelqu'un dit qu'il est optimisé par défaut par n'importe quel compilateur moderne "intelligent". En passant, regardez les résultats sans optimisation. J'ai essayé: Code C minimal:
Mon compilateur: g ++ (Ubuntu / Linaro 4.6.3-1ubuntu5) 4.6.3
Commande pour la génération du code d'assemblage: g ++ -S -masm = intel test.cpp
Gotten assembly code at the output:...
L3:
mov DWORD PTR [esp],97
call putchar
add DWORD PTR [esp+40],1.L2:
THIS LOOP IS HERE
**<b>mov ebx, DWORD PTR [esp+40]
mov eax, DWORD PTR [esp+44]
mov DWORD PTR [esp+28],-1
mov edx, eax
mov eax,0
mov ecx, DWORD PTR [esp+28]
mov edi, edx
repnz scasb</b>**
AS YOU CAN SEE it's done every time
mov eax, ecx
not eax
sub eax, 1
cmp ebx, eax
setb al
test al, al
jne .L3
mov eax, 0
.....
Je répugnerais à faire confiance à tout compilateur qui tenterait de l'optimiser à moins que l'adresse de la chaîne ne soit restrictqualifiée. S'il existe certains cas où une telle optimisation serait légitime, l'effort requis pour identifier de manière fiable de tels cas en l'absence de restrictserait, par toute mesure raisonnable, presque certainement dépasser l'avantage. Si l'adresse de la chaîne avait un const restrictqualificatif, cependant, ce serait suffisant en soi pour justifier l'optimisation sans avoir à regarder autre chose.
supercat
0
En élaborant sur la réponse de Prætorian, je recommande ce qui suit:
for(auto i = strlen(s)-1; i >0;--i ){foo(s[i-1];}
autocar vous ne voulez pas vous soucier du type de retour de strlen. Un compilateur C ++ 11 (par exemplegcc -std=c++0x , pas complètement C ++ 11 mais les types automatiques fonctionnent) le fera pour vous.
i = strlen(s)parce que vous voulez comparer à 0(voir ci-dessous)
i > 0 parce que la comparaison à 0 est (légèrement) plus rapide que la comparaison à tout autre nombre.
L'inconvénient est que vous devez utiliser i-1pour accéder aux caractères de la chaîne.
ss
intérieur de la boucle.ss
n'est jamais modifié, il peut sortir le calcul de la boucle.Réponses:
Oui,
strlen()
sera évalué à chaque itération. Il est possible que, dans des circonstances idéales, l'optimiseur puisse en déduire que la valeur ne changera pas, mais je ne me fierais personnellement pas à cela.Je ferais quelque chose comme
ou éventuellement
tant que la chaîne ne changera pas de longueur pendant l'itération. Si c'est le cas, vous devrez soit appeler à
strlen()
chaque fois, soit le gérer selon une logique plus compliquée.la source
strlen
toute façon.strlen
est marqué comme__attribute__((pure))
permettant au compilateur d'élider plusieurs appels. Attributs GCCOui, chaque fois que vous utilisez la boucle. Ensuite, il calculera à chaque fois la longueur de la chaîne. alors utilisez-le comme ceci:
Dans le code ci-dessus
str[i]
ne vérifie qu'un caractère particulier dans la chaîne à l'emplacementi
chaque fois que la boucle démarre un cycle, donc cela prendra moins de mémoire et sera plus efficace.Consultez ce lien pour plus d'informations.
Dans le code ci-dessous, chaque fois que la boucle s'exécute
strlen
, la longueur de la chaîne entière sera comptée, ce qui est moins efficace, prend plus de temps et prend plus de mémoire.la source
strlen
appel, et si vous êtes aussi serré, vous devriez probablement penser à éliminer quelques autres appels de fonction également ...int strlen(char *s) { int len = 0; while(s[len] != '\0') len++; return len; }
qui est à peu près exactement ce que vous faites dans le code de votre réponse. Je ne dis pas qu'itérer sur la chaîne une fois plutôt que deux est plus efficace en temps , mais je ne vois pas l'un ou l'autre utilisant plus ou moins de mémoire. Ou faites-vous référence à la variable utilisée pour contenir la longueur de la chaîne?Un bon compilateur peut ne pas le calculer à chaque fois, mais je ne pense pas que vous puissiez être sûr que chaque compilateur le fait.
En plus de cela, le compilateur doit savoir que
strlen(ss)
cela ne change pas. Ceci n'est vrai que s'ilss
n'est pas modifié enfor
boucle.Par exemple, si vous utilisez une fonction en lecture seule sur
ss
dansfor
loop mais que vous ne déclarez pas less
paramètre -paramètre commeconst
, le compilateur ne peut même pas savoir que cess
n'est pas changé dans la boucle et doit calculerstrlen(ss)
à chaque itération.la source
ss
pas être changé dans lafor
boucle; il ne doit pas être accessible depuis et modifié par une fonction appelée dans la boucle (soit parce qu'il est passé en argument, soit parce qu'il s'agit d'une variable globale ou d'une variable de portée fichier). La qualification des constants peut également être un facteur.restrict
est pour C99.ss
dans la boucle for, alors même si son paramètre est déclaréconst char*
, le compilateur a encore besoin de recalculer la longueur à moins que (a) il sache quess
pointe vers un objet const, au lieu d'être simplement un pointeur vers const, ou (b) il peut insérer la fonction ou voir autrement qu'elle est en lecture seule. Prendre unconst char*
paramètre n'est pas une promesse de ne pas modifier les données pointées, car il est valide de transtyperchar*
et de modifier à condition que l'objet modifié ne soit pas const et ne soit pas une chaîne littérale.Si
ss
est de typeconst char *
et que vous ne rejetez pas leconst
ness dans la boucle, le compilateur ne peut appelerstrlen
qu'une seule fois, si les optimisations sont activées. Mais ce n'est certainement pas un comportement sur lequel on peut compter.Vous devez enregistrer le
strlen
résultat dans une variable et utiliser cette variable dans la boucle. Si vous ne souhaitez pas créer de variable supplémentaire, en fonction de ce que vous faites, vous pourrez peut-être vous en sortir en inversant la boucle pour itérer en arrière.la source
strlen
du tout. Faites une boucle jusqu'à ce que vous atteigniez la fin.i > 0
? Cela ne devrait-il pas êtrei >= 0
ici? Personnellement, je commencerais aussi parstrlen(s) - 1
itérer sur la chaîne à l'envers, alors la terminaison\0
n'a pas besoin de considération particulière.i >= 0
ne fonctionne que si vous initialisez àstrlen(s) - 1
, mais si vous avez une chaîne de longueur nulle, la valeur initiale est inférieurei > 0
expression lors de l'entrée de boucle initiale? Si ce n'est pas le cas, alors vous avez raison, le cas de longueur nulle rompra définitivement la boucle. Si c'est le cas, vous obtenez "simplement" un signei
== -1 <0 donc pas d'entrée de boucle si le conditionnel esti >= 0
.strlen
Le type de retour de n'est pas signé, donc prend la valeur(strlen(s)-1) >= 0
true pour les chaînes de longueur nulle.Formellement oui,
strlen()
on s'attend à ce qu'il soit appelé à chaque itération.Quoi qu'il en soit, je ne veux pas nier la possibilité de l'existence d'une optimisation intelligente du compilateur, qui optimisera tout appel successif à strlen () après le premier.
la source
Le code du prédicat dans son intégralité sera exécuté à chaque itération de la
for
boucle. Afin de mémoriser le résultat de l'strlen(ss)
appel, le compilateur aurait besoin de savoir qu'au moinsstrlen
était sans effet secondairess
ne change pas pendant la durée de la boucleLe compilateur ne sait ni l'une ni l'autre de ces choses et ne peut donc pas mémoriser en toute sécurité le résultat du premier appel
la source
ss
en unsize_t
ou la diviser entre plusieursbyte
valeurs. Mon thread sournois pourrait alors simplement écrire des octets dans cette adresse et le compilateur aurait un moyen de comprendre à quoi il s'agissaitss
.int a = 0; do_something(); printf("%d",a);
cela ne peut pas être optimisé, car celado_something()
pourrait faire votre chose int non initialisée, ou pourrait remonter la pile et modifiera
délibérément. En fait, gcc 4.5 l'optimisedo_something(); printf("%d",0);
avec -O3Oui . strlen sera calculé à chaque fois que i augmente.
Si vous n'avez pas changé ss avec dans la boucle , cela n'affectera pas la logique, sinon cela affectera.
Il est plus sûr d'utiliser le code suivant.
la source
Oui, le
strlen(ss)
calculera la longueur à chaque itération. Si vous augmentezss
d'une manière ou d'une autre lei
; il y aurait une boucle infinie.la source
Oui, la
strlen()
fonction est appelée à chaque fois que la boucle est évaluée.Si vous voulez améliorer l'efficacité, pensez toujours à tout sauvegarder dans des variables locales ... Cela prendra du temps mais c'est très utile.
Vous pouvez utiliser le code comme ci-dessous:
la source
Oui,
strlen(ss)
sera calculé à chaque exécution du code.la source
Pas courant de nos jours mais il y a 20 ans sur les plates-formes 16 bits, je recommanderais ceci:
Même si votre compilateur n'est pas très intelligent en matière d'optimisation, le code ci-dessus peut encore donner un bon code d'assemblage.
la source
Oui. Le test ne sait pas que ss n'est pas modifié à l'intérieur de la boucle. Si vous savez que cela ne changera pas, j'écrirais:
la source
Arrgh, ça va, même dans des circonstances idéales, bon sang!
À partir d'aujourd'hui (janvier 2018), et gcc 7.3 et clang 5.0, si vous compilez:
Donc nous avons:
ss
est un pointeur constant.ss
est marqué__restrict__
ss
(enfin, sauf s'il viole le__restrict__
).et encore , les deux compilateurs exécutent
strlen()
chaque itération de cette boucle . Incroyable.Cela signifie également que les allusions / vœux pieux de @Praetorian et @JaredPar ne fonctionnent pas.
la source
OUI, en termes simples. Et il y a un petit non dans une condition rare dans laquelle le compilateur le souhaite, comme étape d'optimisation s'il constate qu'il n'y a pas du tout de modifications apportées
ss
. Mais en bon état, vous devriez le penser comme OUI. Il y a des situations comme un programme inmultithreaded
et event, il peut devenir bogué si vous le considérez comme NON. Soyez prudent car cela n'améliorera pas trop la complexité du programme.la source
Oui.
strlen()
calculé à chaque fois lorsqu'ili
augmente et n'est pas optimisé.Le code ci-dessous montre pourquoi le compilateur ne doit pas optimiser
strlen()
.la source
strlen
.Nous pouvons facilement le tester:
La condition de boucle est évaluée après chaque répétition, avant de redémarrer la boucle.
Faites également attention au type que vous utilisez pour gérer la longueur des chaînes. ce devrait être celui
size_t
qui a été défini commeunsigned int
dans stdio. le comparer et le convertirint
peut causer de sérieux problèmes de vulnérabilité.la source
eh bien, j'ai remarqué que quelqu'un dit qu'il est optimisé par défaut par n'importe quel compilateur moderne "intelligent". En passant, regardez les résultats sans optimisation. J'ai essayé:
Code C minimal:
Mon compilateur: g ++ (Ubuntu / Linaro 4.6.3-1ubuntu5) 4.6.3
Commande pour la génération du code d'assemblage: g ++ -S -masm = intel test.cpp
la source
restrict
qualifiée. S'il existe certains cas où une telle optimisation serait légitime, l'effort requis pour identifier de manière fiable de tels cas en l'absence derestrict
serait, par toute mesure raisonnable, presque certainement dépasser l'avantage. Si l'adresse de la chaîne avait unconst restrict
qualificatif, cependant, ce serait suffisant en soi pour justifier l'optimisation sans avoir à regarder autre chose.En élaborant sur la réponse de Prætorian, je recommande ce qui suit:
auto
car vous ne voulez pas vous soucier du type de retour de strlen. Un compilateur C ++ 11 (par exemplegcc -std=c++0x
, pas complètement C ++ 11 mais les types automatiques fonctionnent) le fera pour vous.i = strlen(s)
parce que vous voulez comparer à0
(voir ci-dessous)i > 0
parce que la comparaison à 0 est (légèrement) plus rapide que la comparaison à tout autre nombre.L'inconvénient est que vous devez utiliser
i-1
pour accéder aux caractères de la chaîne.la source