En revanche, lorsque je dois prévoir une chaîne suffisamment grande pour contenir des mots de différentes longueurs, strcmp ne reconnaîtra jamais comme corrects les mots qui ne remplissent pas complètement le tableau (caractère de fin inclus). Ainsi, dans le programme suivant, CHIENS et CHATS ne seront jamais reconnus comme corrects, alors que OISEAUX le sera :
int main(void)
{
char nomAnimal[8];
puts("Que préférez-vous : les chiens, les chats ou les oiseaux ?\n"
"Tapez CHIENS, CHATS ou OISEAUX pour répondre.");
fgets(nomAnimal, 8, stdin);
viderBuffer();
while(strcmp(nomAnimal, "CHIENS") != 0 && strcmp(nomAnimal, "CHATS") != 0 && strcmp(nomAnimal, "OISEAUX") !=0)
{
puts("Saisie invalide. Essayez à nouveau.");
fgets(nomAnimal, 8, stdin);
viderBuffer();
}
puts("SAISIE CORRECTE");
return 0;
}
Est-ce qu'il existe une solution pour régler ce problème ? Merci d'avance pour votre aide.
Mais il le fait aussi quand la chaîne de caractère fait pile la bonne dimension pour contenir la saisie de l'utilisateur et le caractère spécial, non ? (Dans mon premier exemple, fgets devrait rendre "MIOU\n", "PIOU\n" ou "WOUF", puisque j'ai prévu 5 emplacements de mémoire pour ces mots qui font 4 lettres), ou je me trompe ?) Du coup, je ne vois pas en quoi une chaîne plus longue change quoi que ce soit,..
fgets(....,N,....) lit au plus N-1 caractères, et met un \0 après le dernier caractère lu. Si un retour chariot est lu avant que N-1 caractères aient été lus, alors il est mis dans la chaine lue, et l'input se termine.
Mais il le fait aussi quand la chaîne de caractère fait pile la bonne dimension pour contenir la saisie de l'utilisateur et le caractère spécial, non ?
non puisque tu as limité le nombre de caractères à pile poil le nombre de lettre à saisir.
par contre dans ce cas MIOUMIOU est une saisie correcte. (il suffit que les quatre première lettre soit correctes.
(Tiens, c'est curieux ! je croyais avoir déjà répondu tout à l'heure... j'espère que je n'ai pas posté ma réponse dans un mauvais fil.)
Ah d'accord, je pensais en fait que fgets enlevait le \0 pour mettre le \n à la place ; je n'avais pas compris que cette fonctio mettait le \n après le \0.
Du coup, une question : est-ce que c'est une erreur, avec fgets, de ne réserver que 5 emplacements pour des mots de 4 lettres ? (Je veux dire, même si les 5 emplacements m'arrangent dans mon exemple, est-ce que ce n'est pas une mauvaise gestion de la mémoire ?)
Sinon, je vais tenter d'enlever \n à la fin de fgets (j'ai vu que c'était possible) et je reviens vers vous pour vous dire si ça a marché ou non.
J'ai réussi à enlever le '\n' du fgets et maintenant le code fonctionne.
Il me reste une question : même si le code fonctionne parce que (en principe) j'ai enlevé le retour à la ligne, lorsque je choisis un mots pour le stocker dans nomAnimal, je dois encore appuyer deux fois sur entrée dans la console (alors que je n'ai pas le problème avec criAnimal). Est-ce que vous savez pourquoi ?
PS : en lisant le manuel (ou plutôt les explications de "Tutorial Points"), j'ai répondu toute seule à ma question dans le dernier message : si la chaîne de caractères prévoit 4 emplacements pour des lettres + 1 pour le caractère de fin de chaîne, alors fgets doit aussi prévoir 5 emplacements. Pas besoin d'en prévoir un sixième pour le retour à la ligne en plus (à moins que vous ne me disiez le contraire...)
Voici mon code :
void nettoieFgets(char chaine[]) //Enlève le retour à la ligne de fgets
{
char *chercheN = strchr(chaine, '\n');
if (chercheN != NULL)
{
*chercheN = 0;
}
}
int main(void)
{
char criAnimal[5]; // WOUF, MIOU ou PIOU
char nomAnimal[8]; //CHIENS, CHATS ou OISEAUX
int nouvelleSaisie = 0; // 1 = la saisie précédente de l'utilisateur était erronée.
while(strcmp(criAnimal, "WOUF") != 0 && strcmp(criAnimal, "MIOU") != 0 && strcmp(criAnimal, "PIOU") !=0)
{
if (nouvelleSaisie == 0)
{
puts("Vous êtes plutôt WOUF, MIOU ou PIOU ?");
}
else
{
puts("Saisie invalide. Essayez à nouveau.");
}
fgets(criAnimal, 5, stdin);
viderBuffer();
nettoieFgets(criAnimal);
nouvelleSaisie = 1;
}
puts("SAISIE CORRECTE");
nouvelleSaisie = 0;
while(strcmp(nomAnimal, "CHIENS") != 0 && strcmp(nomAnimal, "CHATS") != 0 && strcmp(nomAnimal, "OISEAUX") !=0)
{
if (nouvelleSaisie == 0)
{
puts("Vous êtes plutôt CHIENS, CHATS ou OISEAUX ?");
}
else
{
puts("Saisie invalide. Essayez à nouveau.");
}
fgets(nomAnimal, 8, stdin);
viderBuffer();
nettoieFgets(nomAnimal);
nouvelleSaisie = 1;
}
puts("SAISIE CORRECTE");
nouvelleSaisie = 0;
return 0; }
[EDIT : Michel, je n'avais pas vu ta (votre ?) réponse car nous avons posté presque en même temps.]
Avec une source de documentation plus à jour, getline est dans la norme POSIX depuis 10 ans.
Getline utilise un tampon extensible pour y loger la ligne lue dans un fichier texte où la console, et réalloue ce tampon au besoin.
Intérêt : lit une ligne sans avoir à fixer une limite de taille arbitraire.
On lui passe donc
L'adresse du pointeur vers le début de ligne
L'adresse de l'entier qui contient la taille du tampon
Et bien sûr le FILE* sur lequel on lit
Au début, mettre NULL pour le tampon, et l'adresse d'un entier contenant 0. C'est simple. Utiliser, réutiliser. À la fin, faire un free pour libérer le tampon.
Exemple :
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
int main()
{
char * ligne = NULL;
size_t taille = 0;
int numero = 0;
printf("tapez du texte, STOP pour arreter\n");
do {
getline(& ligne, & taille, stdin);
numero ++;
printf("%d -> %s", numero, ligne);
}
while (strncmp(ligne, "STOP\n", 5) != 0);
free(ligne);
return 0;
}
- Edité par michelbillaud 1 juillet 2019 à 10:31:22
Il me reste une question : même si le code fonctionne parce que (en principe) j'ai enlevé le retour à la ligne, lorsque je choisis un mots pour le stocker dans nomAnimal, je dois encore appuyer deux fois sur entrée dans la console (alors que je n'ai pas le problème avec criAnimal). Est-ce que vous savez pourquoi ?
Probablement ta fonction viderBuffer qui bloque sur getchar car le buffer clavier est déjà vide !
Merci Rouloude, je ne voyais pas du tout ce que ça pouvait être.
Michel : la fonction getline est beaucoup plus simple à comprendre avec tes explications. Seulement, je me demande : est-ce que cette norme POSIX est portable sur Windows et Mac ? (D'après Wikipedia, la norme POSIX de 1990 est portable sur Windows, mais je ne sais pas ce qu'il en est pour getline, de 20 ans plus récent. Est-ce qu'il y a un site sur lequel je peux me renseigner ? Le seul article un peu récent sur getline que j'aie trouvé (https://blog.udemy.com/c-getline/) n'en parle pas.) En tout cas, un grand merci, car tu es souvent là pour répondre à mes questions.
je n'utilise ni l'un ni l'autre, mais je veux bien essayer si on m'offre un ordinateur pour chaque.
Problème avec strcmp
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent