5
votes

Le calcul de la longueur de la chaîne n'est pas correct lors de l'impression de la valeur de retour d'un programme

La longueur est supposée renvoyer la distance parcourue par le compteur en passant par la chaîne. Cependant, il ne renvoie la valeur correcte que lorsqu'il est imprimé au préalable. Si je commente le printf , il renvoie 0. Quelqu'un at-il une explication à cela?

#include<stdio.h>
#include<string.h>
#define MAX 100

int length(char *s) {
    int i;
    for (i = 0; s[i] != '\0'; ++i)
        printf("%d ", i);           //<-- here
    return i;
}

int main() 
{
    char s[MAX];
    fgets(s, (char)sizeof(s), stdin);
    s[strcspn(s, "\n")]='\0';
    printf("Length: %d\n", length(s));
    return 0;
}


1 commentaires

C'est pourquoi vous utilisez toujours des crochets {} ^^


3 Réponses :


7
votes

Le problème est que si vous commentez l'instruction printf () dans la fonction length () , l'instruction return devient une partie de le corps de la boucle, et la toute première itération revient de l'appel et vous obtenez la valeur the-then de i , qui est juste la valeur d'entrée de la boucle, 0 .

while (s[i] != '\0') 
{
    i++;                     //increment statement is explicit.
}

est le même que

for (int i = 0; i < 10; i++) 
    {/*nothing here*/}       //indicates empty loop body
return i;

Ce dont vous avez besoin est la boucle pour terminer l'exécution, appuyez sur le bouton critères de sortie, puis exécutez l'instruction return avec la dernière valeur de i .

Donc, pour éviter le problème, vous pouvez imposer une exécution vide de la boucle, par quelque chose comme

for (i = 0; s[i] != '\0'; ++i) ;   // notice the ; here, ends the scope.
return i; 

ou, encore mieux (pour les lecteurs)

for (i = 0; s[i] != '\0'; ++i)
return i;                                

Remarque: comme alternative, pour améliorer la lisibilité, au lieu d'une construction for , vous pouvez également utiliser boucle while , qui va comme

for (i = 0; s[i] != '\0'; ++i)
    //printf("%d ", i);           //<-- here
return i;                         // without brace-enfoced scope, this is the loop body.


4 commentaires

Donc ce que vous dites, si je n'ai pas de point-virgule, quelle que soit la distance, la première instruction après la boucle sera exécutée. Correct?


Voici une situation où la boucle while doit être utilisée à la place de la boucle for où l'incrément prend place à l'intérieur des accolades.


@Michi Vous voulez dire, rendez l'incrémentation de l'index explicite en le mettant comme corps de boucle pour la construction while , non?


@Sourav Ghosh. Droite. :))



5
votes

Dans une boucle comme celle-ci:

for (...)
    ; // yes, a hanging semicolon

// or like this:
for (...);

statement1 sera la seule chose exécutée dans la boucle. Lorsque vous commentez l'appel printf , return i; est exécuté à la toute première itération, renvoyant immédiatement zéro.

Notez cependant que statement1 peut être vide, donc, pour exécuter une boucle sans corps, faites:

for (...)
    statement1;
statement2;


0 commentaires

3
votes

Si vous venez de sortir ce printf , il vous restera ceci:

int length(char *s) {
    int i;
    for (i = 0; s[i] != '\0'; ++i) {
        printf("%d ", i);           //<-- here
    }
    return i;
}

Ceci est égal à:

for (i = 0; s[i] != '\0'; ++i);


2 commentaires

Encore mieux est de toujours utiliser des accolades explicites sur les boucles, les conditions, etc., alors des problèmes comme celui-ci ne peuvent pas se produire. En perl par exemple, les accolades explicites sont même obligatoires.


Bonne suggestion, j'ai ajouté une version de la façon dont la fonction pourrait ressembler à ceci.