2016-06-28 3 views
3

J'écris un programme pour le fun (pas pour l'école), et j'ai du mal à comprendre pourquoi la fonction scanf ne s'exécute pas à chaque itération de ma boucle - I ' ve joué avec les boucles 'for' et les boucles 'while'.scanf ne s'exécute pas sur chaque boucle itération

Je sais que selon la façon dont j'écris la fonction scanf (à savoir scanf("%s", &variablename); VS scanf("%99[^\n]s", &variablename);) fait une différence, mais j'ai tout essayé et je suis désespérée!

Quand je fais un printf contrôle sur mon entrée du scanf, à chaque itération, il est seulement ASPIRATION une chaîne par itération, donc si j'entre deux mots dans ma première entrée, puis il faut compter deux itérations à traiter - un mot par. Voici le segment de code que je décris:

int main(void){ 
    int tries = 0; 
    int score = 0; 
    char question[100]; 
    char useranswer[100]; 
    const char *phrase = {"our favorite saying\0"}; 

    printf("\nQuestion #3 (10 points): What is our secret saying?\n"); 
     sleep(1); 
     tries = 1; 

    while (tries<=3){ 
     printf("YOUR ANSWER:"); 
     scanf("%s[^\n]", useranswer); 

     if(strncmp(useranswer, phrase, 15) != 0){ 
      printf ("Nope, try again!\n"); 
      printf("You have used %d out of 3 tries!\n", tries); 
      if (tries == 2){ 
       printf("Here's your final hint:xxx...\n"); 
      } 
      if (tries == 3){ 
      printf("You didn't get it. The answer is: our favorite saying!\n"); 
      } 
      tries++; 
     } 
     if (strncmp(useranswer, phrase, 15) == 0){ 
      printf("Damn, you're good. Well done.\n"); 
      score += 10; 
      break; 
     } 
    } 

La sortie de ce code est:

Question #3 (10 points): What is our secret saying? 
YOUR ANSWER:our favorite saying 
Nope, try again! 
You have used 1 out of 3 tries! 
YOUR ANSWER:Nope, try again! 
You have used 2 out of 3 tries! 
Here's your final hint:xxx... 
YOUR ANSWER:Nope, try again! 
You have used 3 out of 3 tries! 
You didn't get it. The answer is: our favorite saying! 

(Il ne m'a permis d'entrer une fois, et je typé « notre dicton favori ».

+5

'scanf ("% 99 [^ \ n]% * c ", réponse utilisateur); ' – BLUEPIXY

+1

Le' [...] 'n'est pas un add-on pour le spécificateur' s' ... c'est un spécificateur de format différent en lui-même. '% s' lit la chaîne suivante de caractères non-espaces, et'% [^ \ n] '(* not *'% s [^ \ n] ') lit une chaîne de tous les caractères sauf' \ n' - donc le code que vous venez de lire chaque mot un à la fois (un par boucle). – Dmitri

+3

'"% s [^ \ n] "' n'est pas un format 'scanf()' valide.Suggérer d'utiliser 'fgets (useranser, sizeof useranswer, stdin)' à la place. – chux

Répondre

3

Dans les commentaires, vous pouvez trouver pourquoi votre spécificateur de format dans scanf ne fonctionne pas.

Une alternative est d'utiliser à la place fgets, peut-être dans une fonction d'aide qui prend soin de quelques-uns des cas marginaux qui peuvent survenir lors de la lecture d'entrée utilisateur:

#include <ctype.h> 

char *read_line(char *buf, size_t n, FILE *pfin) 
{ 
    ssize_t length = 0; 
    int ch; 

    if (!buf || n == 0) 
     return NULL; 
    /* Consume trailing control characters, like '\0','\n', '\r', '\f'... 
     but also '\t'. Note that ' ' is not skipped. */ 
    while ((ch = fgetc(pfin)) != EOF && iscntrl(ch)) { } 
    if (ch == EOF) 
     return NULL; 
    /* At least one char is printable */ 
    *buf = ch; 
    ++length; 

    /* Read from file till a newline or up to n-2 chars. The remaining chars 
     are left in the stream buffer. Return NULL if no char is read.  */ 
    if (fgets(buf + 1, n - 1, pfin)) 
    { 
     /* Trim the string to the first control character     */ 
     while (!iscntrl(buf[length])) 
     { 
      ++length; 
     } 
     buf[length] = '\0';  
    } 
    return buf; 
} 

je changerais aussi la logique suivante. OP utilise strncmp(useranswer, phrase, 15) plusieurs fois, mais ce nombre magique 15 est inférieur à la taille de phrase donc il finit par ne comparer qu'une sous-chaîne.

while (tries <= 3) { 
    printf("YOUR ANSWER:"); 
    if (!read_line(useranswer, sizeof useranswer, stdin)) { 
     printf("Error: Unexpected end of input.\n"); 
     exit(EXIT_FAILURE); 
    } 
    if(strcmp(useranswer, phrase) == 0) { 
     printf("Damn, you're good. Well done.\n"); 
     score += 10; 
     break; 
    } else { 
     printf ("Nope, try again!\n"); 
     printf("You have used %d out of 3 tries!\n", tries); 
     if (tries == 2) { 
      printf("Here's your final hint:xxx...\n"); 
     } 
     if (tries == 3) { 
      printf("You didn't get it. The answer is: our favorite saying!\n"); 
     } 
     tries++; 
    } 
} 


Comme note finale, je trouve la déclaration OP de phrase un peu bizarre (peut-être une faute de frappe):

const char *phrase = {"our favorite saying\0"}; 
//   string literals are already ^^ null terminated... 

Alors que nous pouvons utiliser une déclaration de tableau simple, comme:

const char phrase[] = "our favorite saying"; 

Considérons également quelles valeurs sizeof phrase renvoie dans ces deux cas différents.


Merci à @chux pour tous les précieux conseils et des liens intéressants fournis:
https://stackoverflow.com/a/27729970/4944425
https://stackoverflow.com/a/28462221/4944425
Et @Dmitri pour avoir souligné dans son commentaire qu'une fois que nous sommes sûrs que les deux chaînes sont terminées par un caractère nul, nous pouvons utiliser strcmp au lieu de strncmp.

+0

Considérez http://stackoverflow.com/a/28462221/2410359 ou http://stackoverflow.com/a/27729970/2410359 pour supprimer le potentiel «\ n». 'if (useranswer [lstr - 1] == '\ n')' n'est pas sûr. – chux

+0

@Dmitri si l'utilisateur entre une chaîne plus longue, la première partie de la condition 'lstr == strlen (phrase)' sera fausse. J'ai suivi l'utilisation de 'strncmp' par OP mais notez qu'il a utilisé' 15' comme un nombre magique. –

+0

@chux oui je n'ai pas vérifié les lignes vides, mon mauvais. –