Problème : 2 scanfs à rentrer deux fois dont le second foire
Résolu/Fermé
tinkilechat
Messages postés
15
Date d'inscription
mercredi 26 juin 2013
Statut
Membre
Dernière intervention
11 juillet 2013
-
26 juin 2013 à 13:51
[Dal] Messages postés 6203 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 29 janvier 2025 - 11 juil. 2013 à 18:10
[Dal] Messages postés 6203 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 29 janvier 2025 - 11 juil. 2013 à 18:10
4 réponses
[Dal]
Messages postés
6203
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
29 janvier 2025
1 099
Modifié par [Dal] le 26/06/2013 à 14:24
Modifié par [Dal] le 26/06/2013 à 14:24
Salut tinkilechat,
En C, on compare les chaînes avec strcmp (définie dans string.h).
http://www.cplusplus.com/reference/cstring/strcmp/
C'est mieux d'utiliser fgets pour récupérer la saisie (comme dans l'exemple proposé dans la page ci-dessus), car cette commande va te permettre de contrôler l'absence de dépassement de la capacité de mémoire allouée, contrairement à scanf que tu utilises.
http://www.cplusplus.com/reference/cstdio/fgets/
Il faudra penser à retirer '\n' qui peut se glisser si l'utilisateur tape quelque chose ayant une taille inférieure à la taille spécifiée, pour ne pas fausser tes comparaisons.
Dal
Edit : précision sur '\n'
En C, on compare les chaînes avec strcmp (définie dans string.h).
http://www.cplusplus.com/reference/cstring/strcmp/
C'est mieux d'utiliser fgets pour récupérer la saisie (comme dans l'exemple proposé dans la page ci-dessus), car cette commande va te permettre de contrôler l'absence de dépassement de la capacité de mémoire allouée, contrairement à scanf que tu utilises.
http://www.cplusplus.com/reference/cstdio/fgets/
Il faudra penser à retirer '\n' qui peut se glisser si l'utilisateur tape quelque chose ayant une taille inférieure à la taille spécifiée, pour ne pas fausser tes comparaisons.
Dal
Edit : précision sur '\n'
tinkilechat
Messages postés
15
Date d'inscription
mercredi 26 juin 2013
Statut
Membre
Dernière intervention
11 juillet 2013
1 juil. 2013 à 22:37
1 juil. 2013 à 22:37
Problème résolut ! Merci fiddy, mais (je ne vais pas encore mettre la balise pour cette raison), il me reste un problème : code::block me signale que la structure "joueur" (que j'ai pourtant déclarée au début du code) n'est pas déclarée (error: 'joueur' undeclared (first use in this function)) et cela, SEULEMENT à la ligne joueur.pseudo = "%s", pseudo;... Cette erreur ne m'est étrangement pas reportée aux ligne joueur.niveau = 1; et joueur.classe = "%s", classe;, seulement à la ligne joueur.pseudo = "%s", pseudo;... Du coup, le programme ne se lance pas à cause de cette "erreur"...
Si vous pouviez m'aider, ce serait sympa de votre part !
Cordialement, tinkilechat.
fichiers :
*main.c :
#include <stdio.h>
#include <stdlib.h>
#include "fichier.h"
#include <string.h>
int main(int argc, char *argv [])
{
int numeroJoueur = 1;
int continuer = 0;
char pseudo [50], classe[50], continuerPseudoClasse[50];
char guerrier[] = "guerrier", paladin[] = "paladin", mage[] = "mage", archer[] = "archer", voleur[] = "voleur";
while (strcmp(pseudo, guerrier) != 0 || strcmp(pseudo, paladin) != 0 || strcmp(pseudo, mage) != 0 || strcmp(pseudo, archer) != 0 || strcmp(pseudo, voleur) != 0)
{
do
{
Player joueur;
joueur.niveau = 1;
printf("Nouveau joueur numero %d, veuillez rentrez votre pseudonyme et choisissez votre \nclasse\nVotre pseudonyme : ", numeroJoueur);
scanf("%s", pseudo);
} while (strcmp(pseudo, continuerPseudoClasse) == 0);
joueur.pseudo = "%s", pseudo;
printf("\n\nBienvenue %s\n Veulliez selectionner votre classe : \nguerrier\n paladin\n mage\n archer\n voleur\n\n", pseudo);
while (strcmp(pseudo, guerrier) != 0 || strcmp(pseudo, paladin) != 0 || strcmp(pseudo, mage) != 0 || strcmp(pseudo, archer) != 0 || strcmp(pseudo, voleur) != 0)
{
scanf ("%s", classe);
if (strcmp(pseudo, guerrier) == 0)
{
printf ("\n\nVous etes desormais un noble et valeureux guerrier !\n\n");
}
else if (strcmp(pseudo, paladin) == 0)
{
printf ("\n\nAllez dans l'honneur (achievement get : to quote Wow) !\n\n");
}
else if (strcmp(pseudo, mage) == 0)
{
printf ("\n\nHooo, vous maitrisez les arcanes ?\n\n");
}
else if (strcmp(pseudo, archer) == 0)
{
printf ("\n\nQue vos fleches transpercent nos ennemis !\n\n");
}
else if (strcmp(pseudo, voleur) == 0)
{
printf ("\n\nHonte a vous, brigand !\\");
}
else
{
printf ("\n\nVeuillez entrer un nom de classe valide.\n\n");
}
joueur.classe = "%s", classe;
}
numeroJoueur ++;
printf ("Nouveau joueur ?\n\n 0 = non\n 1 = oui\n");
scanf ("%d", &continuer);
}while (continuer);
return 0;
}
*fichier.h :
#ifndef FICHIER_H_INCLUDED
#define FICHIER_H_INCLUDED
typedef struct Player Player;
struct Player
{
char pseudo[20];
char classe[9];
int niveau;
};
#endif // FICHIER_H_INCLUDED
Si vous pouviez m'aider, ce serait sympa de votre part !
Cordialement, tinkilechat.
fichiers :
*main.c :
#include <stdio.h>
#include <stdlib.h>
#include "fichier.h"
#include <string.h>
int main(int argc, char *argv [])
{
int numeroJoueur = 1;
int continuer = 0;
char pseudo [50], classe[50], continuerPseudoClasse[50];
char guerrier[] = "guerrier", paladin[] = "paladin", mage[] = "mage", archer[] = "archer", voleur[] = "voleur";
while (strcmp(pseudo, guerrier) != 0 || strcmp(pseudo, paladin) != 0 || strcmp(pseudo, mage) != 0 || strcmp(pseudo, archer) != 0 || strcmp(pseudo, voleur) != 0)
{
do
{
Player joueur;
joueur.niveau = 1;
printf("Nouveau joueur numero %d, veuillez rentrez votre pseudonyme et choisissez votre \nclasse\nVotre pseudonyme : ", numeroJoueur);
scanf("%s", pseudo);
} while (strcmp(pseudo, continuerPseudoClasse) == 0);
joueur.pseudo = "%s", pseudo;
printf("\n\nBienvenue %s\n Veulliez selectionner votre classe : \nguerrier\n paladin\n mage\n archer\n voleur\n\n", pseudo);
while (strcmp(pseudo, guerrier) != 0 || strcmp(pseudo, paladin) != 0 || strcmp(pseudo, mage) != 0 || strcmp(pseudo, archer) != 0 || strcmp(pseudo, voleur) != 0)
{
scanf ("%s", classe);
if (strcmp(pseudo, guerrier) == 0)
{
printf ("\n\nVous etes desormais un noble et valeureux guerrier !\n\n");
}
else if (strcmp(pseudo, paladin) == 0)
{
printf ("\n\nAllez dans l'honneur (achievement get : to quote Wow) !\n\n");
}
else if (strcmp(pseudo, mage) == 0)
{
printf ("\n\nHooo, vous maitrisez les arcanes ?\n\n");
}
else if (strcmp(pseudo, archer) == 0)
{
printf ("\n\nQue vos fleches transpercent nos ennemis !\n\n");
}
else if (strcmp(pseudo, voleur) == 0)
{
printf ("\n\nHonte a vous, brigand !\\");
}
else
{
printf ("\n\nVeuillez entrer un nom de classe valide.\n\n");
}
joueur.classe = "%s", classe;
}
numeroJoueur ++;
printf ("Nouveau joueur ?\n\n 0 = non\n 1 = oui\n");
scanf ("%d", &continuer);
}while (continuer);
return 0;
}
*fichier.h :
#ifndef FICHIER_H_INCLUDED
#define FICHIER_H_INCLUDED
typedef struct Player Player;
struct Player
{
char pseudo[20];
char classe[9];
int niveau;
};
#endif // FICHIER_H_INCLUDED
fiddy
Messages postés
11069
Date d'inscription
samedi 5 mai 2007
Statut
Contributeur
Dernière intervention
23 avril 2022
1 844
Modifié par fiddy le 1/07/2013 à 22:46
Modifié par fiddy le 1/07/2013 à 22:46
joueur.pseudo = "%s", pseudo;
Ca ne veut rien dire cette ligne. Le "%s" dans les les scanf/printf/etc. joueur.pseudo=pseudo; serait déjà plus logique. Mais ce n'est pas correct non plus, pour copier une chaîne on utilise strcpy : strcpy(joueur.pseudo, pseudo);
Ou sinon plutôt que faire scanf("%s", pseudo); tu peux directement faire : scanf("%s",joueur.pseudo);
Sinon, c'est normal que le compilateur ne connaisse pas "joueur". Tu l'as déclarée dans le do while. Et tu définies "joueur" en dehors de la boucle. Déclare-le plutôt dans le while { ... }.
Ca ne veut rien dire cette ligne. Le "%s" dans les les scanf/printf/etc. joueur.pseudo=pseudo; serait déjà plus logique. Mais ce n'est pas correct non plus, pour copier une chaîne on utilise strcpy : strcpy(joueur.pseudo, pseudo);
Ou sinon plutôt que faire scanf("%s", pseudo); tu peux directement faire : scanf("%s",joueur.pseudo);
Sinon, c'est normal que le compilateur ne connaisse pas "joueur". Tu l'as déclarée dans le do while. Et tu définies "joueur" en dehors de la boucle. Déclare-le plutôt dans le while { ... }.
while (strcmp(pseudo, guerrier) != 0 || strcmp(pseudo, paladin) != 0 || strcmp(pseudo, mage) != 0 || strcmp(pseudo, archer) != 0 || strcmp(pseudo, voleur) != 0) { Player joueur; do>
tinkilechat
Messages postés
15
Date d'inscription
mercredi 26 juin 2013
Statut
Membre
Dernière intervention
11 juillet 2013
2 juil. 2013 à 00:19
2 juil. 2013 à 00:19
Ok ! Encore une fois, merci fiddy ! :3
tinkilechat
Messages postés
15
Date d'inscription
mercredi 26 juin 2013
Statut
Membre
Dernière intervention
11 juillet 2013
2 juil. 2013 à 17:51
2 juil. 2013 à 17:51
Bien maintenant, le problème n°1 est résolut mais il y a toujours le 2ème : quoi que l'on rentre dans la chaîne classe[50], elle ne sera jamais égale aux chaînes de test (strcmp (pseudo, chaînedetest) == 0) tels que guerrier[], mage[], archer[] (Et ce même si ces dernières ont la même taille.)... Pouvez-vous m'aider s'il vous plaît ? Merci.
Pour tester, voici une nouvelle fois le code du main.c (le fichier.h n'a pas changé quant à lui) :
#include <stdio.h>
#include <stdlib.h>
#include "fichier.h"
#include <string.h>
int main(int argc, char *argv [])
{
int numeroJoueur = 1;
int continuer = 0;
char pseudo [50], classe[50], continuerPseudoClasse[50];
char guerrier[] = "guerrier", paladin[] = "paladin", mage[] = "mage", archer[] = "archer", voleur[] = "voleur";
do
{
Player joueur;
joueur.niveau = 1;
do
{
printf("Nouveau joueur numero %d, veuillez rentrez votre pseudonyme et choisissez votre \nclasse\n\nVotre pseudonyme : ", numeroJoueur);
scanf("%s", pseudo);
strcpy (joueur.pseudo, pseudo);
} while (strcmp(pseudo, continuerPseudoClasse) == 0);
printf("\n\nBienvenue %s\n\n Veulliez selectionner votre classe :\n \nguerrier\n paladin\n mage\n archer\n voleur\n\n Votre classe : ", pseudo);
while (strcmp(pseudo, guerrier) != 0 || strcmp(pseudo, paladin) != 0 || strcmp(pseudo, mage) != 0 || strcmp(pseudo, archer) != 0 || strcmp(pseudo, voleur) != 0)
{
scanf ("%s", classe);
if (strcmp(pseudo, guerrier) == 0)
{
printf ("\n\nVous etes desormais un noble et valeureux guerrier !\n\n");
}
else if (strcmp(pseudo, paladin) == 0)
{
printf ("\n\nAllez dans l'honneur (achievement get : to quote Wow) !\n\n");
}
else if (strcmp(pseudo, mage) == 0)
{
printf ("\n\nHooo, vous maitrisez les arcanes ?\n\n");
}
else if (strcmp(pseudo, archer) == 0)
{
printf ("\n\nQue vos fleches transpercent nos ennemis !\n\n");
}
else if (strcmp(pseudo, voleur) == 0)
{
printf ("\n\nHonte a vous, brigand !\\");
}
else
{
printf ("\n\nVeuillez entrer un nom de classe valide.\n\n");
}
strcpy (joueur.classe, classe);
}
numeroJoueur ++;
printf ("Nouveau joueur ?\n\n 0 = non\n 1 = oui\n");
scanf ("%d", &continuer);
}while (continuer);
return 0;
}
Pour tester, voici une nouvelle fois le code du main.c (le fichier.h n'a pas changé quant à lui) :
#include <stdio.h>
#include <stdlib.h>
#include "fichier.h"
#include <string.h>
int main(int argc, char *argv [])
{
int numeroJoueur = 1;
int continuer = 0;
char pseudo [50], classe[50], continuerPseudoClasse[50];
char guerrier[] = "guerrier", paladin[] = "paladin", mage[] = "mage", archer[] = "archer", voleur[] = "voleur";
do
{
Player joueur;
joueur.niveau = 1;
do
{
printf("Nouveau joueur numero %d, veuillez rentrez votre pseudonyme et choisissez votre \nclasse\n\nVotre pseudonyme : ", numeroJoueur);
scanf("%s", pseudo);
strcpy (joueur.pseudo, pseudo);
} while (strcmp(pseudo, continuerPseudoClasse) == 0);
printf("\n\nBienvenue %s\n\n Veulliez selectionner votre classe :\n \nguerrier\n paladin\n mage\n archer\n voleur\n\n Votre classe : ", pseudo);
while (strcmp(pseudo, guerrier) != 0 || strcmp(pseudo, paladin) != 0 || strcmp(pseudo, mage) != 0 || strcmp(pseudo, archer) != 0 || strcmp(pseudo, voleur) != 0)
{
scanf ("%s", classe);
if (strcmp(pseudo, guerrier) == 0)
{
printf ("\n\nVous etes desormais un noble et valeureux guerrier !\n\n");
}
else if (strcmp(pseudo, paladin) == 0)
{
printf ("\n\nAllez dans l'honneur (achievement get : to quote Wow) !\n\n");
}
else if (strcmp(pseudo, mage) == 0)
{
printf ("\n\nHooo, vous maitrisez les arcanes ?\n\n");
}
else if (strcmp(pseudo, archer) == 0)
{
printf ("\n\nQue vos fleches transpercent nos ennemis !\n\n");
}
else if (strcmp(pseudo, voleur) == 0)
{
printf ("\n\nHonte a vous, brigand !\\");
}
else
{
printf ("\n\nVeuillez entrer un nom de classe valide.\n\n");
}
strcpy (joueur.classe, classe);
}
numeroJoueur ++;
printf ("Nouveau joueur ?\n\n 0 = non\n 1 = oui\n");
scanf ("%d", &continuer);
}while (continuer);
return 0;
}
[Dal]
Messages postés
6203
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
29 janvier 2025
1 099
Modifié par [Dal] le 2/07/2013 à 19:08
Modifié par [Dal] le 2/07/2013 à 19:08
Salut,
Alors, on va commencer par cela :
En faisant :
Tu compares la chaîne pointée par "pseudo", qui vient d'être tapée par l'utilisateur à la chaine pointée par "continuerPseudoClasse". Sauf que la chaîne pointée par "continuerPseudoClasse" n'est pas initialisée. Tu t'es contenté de créer un espace mémoire vers 50 octets, qui contiennent quelque chose d'imprévisible.
Alors, à moins que l'utilisateur soit très fort, il y a de fortes chances que quoi qu'il tape, il n'arrivera jamais à boucler, et ton test ne sert à rien...
En conclusion : tu veux comparer la chaîne pointée par "pseudo" tapée par l'utilisateur à quoi .. et pourquoi fais-tu cela : que veux-tu vérifier ?
Deuxièmement, si tu ne veux pas utiliser fgets, tant pis pour toi :-), mais alors vérifie la taille de la saisie avec l'astuce de fiddy concernant scanf, et prends la peine de flusher après chaque scanf le buffer clavier.
Sous réserve de clarification de ton test (et aussi des autres problèmes signalés ci-après liés à ta structure de données), un code correct possible, limité à la première boucle serait :
Après chaque scanf, purge stdin.
Je n'ai pas regardé en détails le reste du code, mais je crois que tu devrais nous expliquer en mots simples ce qu'il devrait faire selon toi (décris ton algorithme). Ce qui est sûr, c'est que avec un seul "Player" définit, tu ne vas écraser les données précédemment saisies en mémoire si tu crées de nouveaux joueurs.
Il faudrait que "joueur" soit un tableau de Player.
Par ailleurs, si une mauvaise "classe" est saisie, tu affectes quand même le résultat de la saisie et proposes la création d'un nouveau joueur.
Aussi, je vois que tu as définit Player comme étant un alias de la struct suivante :
harmonise la taille de ta structure de données par rapport à ce que l'utilisateur peut saisir, sinon tu cours au débordement et strcpy ne va pas faire cette vérification pour toi.
Enfin, pour tes comparaisons, c'est normal que cela ne donne rien, car tu compares "pseudo" à tes chaînes.... alors que ce que tu veux comparer c'est, je pense, ce que l'utilisateur a saisit dans "classe".
;-)
Dal
Alors, on va commencer par cela :
En faisant :
(...) char pseudo[50], classe[50], continuerPseudoClasse[50]; (...) do { printf( "Nouveau joueur numero %d, veuillez rentrez votre pseudonyme et choisissez votre \nclasse\n\nVotre pseudonyme : ", numeroJoueur); scanf("%s", pseudo); strcpy(joueur.pseudo, pseudo); } while (strcmp(pseudo, continuerPseudoClasse) == 0);
Tu compares la chaîne pointée par "pseudo", qui vient d'être tapée par l'utilisateur à la chaine pointée par "continuerPseudoClasse". Sauf que la chaîne pointée par "continuerPseudoClasse" n'est pas initialisée. Tu t'es contenté de créer un espace mémoire vers 50 octets, qui contiennent quelque chose d'imprévisible.
Alors, à moins que l'utilisateur soit très fort, il y a de fortes chances que quoi qu'il tape, il n'arrivera jamais à boucler, et ton test ne sert à rien...
En conclusion : tu veux comparer la chaîne pointée par "pseudo" tapée par l'utilisateur à quoi .. et pourquoi fais-tu cela : que veux-tu vérifier ?
Deuxièmement, si tu ne veux pas utiliser fgets, tant pis pour toi :-), mais alors vérifie la taille de la saisie avec l'astuce de fiddy concernant scanf, et prends la peine de flusher après chaque scanf le buffer clavier.
Sous réserve de clarification de ton test (et aussi des autres problèmes signalés ci-après liés à ta structure de données), un code correct possible, limité à la première boucle serait :
do { printf("Nouveau joueur numero %d, veuillez saisir " "votre pseudonyme et choisir votre\n" "classe\n" "Votre pseudonyme : ", numeroJoueur); scanf("%49[^\n]", pseudo); char c; while ((c = getchar()) != '\n' && c != EOF) /* purger stdin */ ; } while (strcmp(pseudo, continuerPseudoClasse) == 0);
Après chaque scanf, purge stdin.
Je n'ai pas regardé en détails le reste du code, mais je crois que tu devrais nous expliquer en mots simples ce qu'il devrait faire selon toi (décris ton algorithme). Ce qui est sûr, c'est que avec un seul "Player" définit, tu ne vas écraser les données précédemment saisies en mémoire si tu crées de nouveaux joueurs.
Il faudrait que "joueur" soit un tableau de Player.
Par ailleurs, si une mauvaise "classe" est saisie, tu affectes quand même le résultat de la saisie et proposes la création d'un nouveau joueur.
Aussi, je vois que tu as définit Player comme étant un alias de la struct suivante :
struct Player { char pseudo[20]; char classe[9]; int niveau; };
harmonise la taille de ta structure de données par rapport à ce que l'utilisateur peut saisir, sinon tu cours au débordement et strcpy ne va pas faire cette vérification pour toi.
Enfin, pour tes comparaisons, c'est normal que cela ne donne rien, car tu compares "pseudo" à tes chaînes.... alors que ce que tu veux comparer c'est, je pense, ce que l'utilisateur a saisit dans "classe".
;-)
Dal
tinkilechat
Messages postés
15
Date d'inscription
mercredi 26 juin 2013
Statut
Membre
Dernière intervention
11 juillet 2013
3 juil. 2013 à 19:27
3 juil. 2013 à 19:27
Je comprend rien ! fgets ? flusher ? buffer ?
Je ne comprend même pas cette partie de code :
scanf("%49[^\n]", pseudo);
char c;
while ((c = getchar()) != '\n' && c != EOF)
/* purger stdin */
J'ai encore du chemin à faire avant de pouvoir m'estimer savoir programmer, hein ? :'-(
P.S. : Par contre, je me suis trompé : j'ai bel et bien changé le fichier.h (j'ai modifié les tailles des chaînes de caractères de struct player à 50) :
#ifndef FICHIER_H_INCLUDED
#define FICHIER_H_INCLUDED
typedef struct Player Player;
struct Player
{
char pseudo[50];
char classe[50];
int niveau;
};
#endif // FICHIER_H_INCLUDED
Je ne comprend même pas cette partie de code :
scanf("%49[^\n]", pseudo);
char c;
while ((c = getchar()) != '\n' && c != EOF)
/* purger stdin */
J'ai encore du chemin à faire avant de pouvoir m'estimer savoir programmer, hein ? :'-(
P.S. : Par contre, je me suis trompé : j'ai bel et bien changé le fichier.h (j'ai modifié les tailles des chaînes de caractères de struct player à 50) :
#ifndef FICHIER_H_INCLUDED
#define FICHIER_H_INCLUDED
typedef struct Player Player;
struct Player
{
char pseudo[50];
char classe[50];
int niveau;
};
#endif // FICHIER_H_INCLUDED
tinkilechat
Messages postés
15
Date d'inscription
mercredi 26 juin 2013
Statut
Membre
Dernière intervention
11 juillet 2013
3 juil. 2013 à 19:52
3 juil. 2013 à 19:52
Ce que je voulais c'était :
DéBUT DU PROGRAMME
v
message de bienvenue + <=======================================||
message pour le pseudomyme ||
v ||
l'utilisateur rentre un pseudonyme <========|| ||
v || ||
L'utilisateur a-t'il rentré un pseudomyme ? =non> ||
(condition inutile) ||
|| ||
oui ||
v ||
message pour la classe ||
v ||
l'utilisateur rentre sa classe <===============================|| ||
v || ||
La classe rentrée par l'utilisateur=non> message "classe non valide">|| ||
est-elle valide ? ||
|| ||
oui ||
v ||
message lié à la classe choisie ||
(ex "Honte à vous, brigand !") ||
v ||
Autre joueur ?=oui>==============================================||
||
non
v
FIN DU PROGRAMME
DéBUT DU PROGRAMME
v
message de bienvenue + <=======================================||
message pour le pseudomyme ||
v ||
l'utilisateur rentre un pseudonyme <========|| ||
v || ||
L'utilisateur a-t'il rentré un pseudomyme ? =non> ||
(condition inutile) ||
|| ||
oui ||
v ||
message pour la classe ||
v ||
l'utilisateur rentre sa classe <===============================|| ||
v || ||
La classe rentrée par l'utilisateur=non> message "classe non valide">|| ||
est-elle valide ? ||
|| ||
oui ||
v ||
message lié à la classe choisie ||
(ex "Honte à vous, brigand !") ||
v ||
Autre joueur ?=oui>==============================================||
||
non
v
FIN DU PROGRAMME
tinkilechat
Messages postés
15
Date d'inscription
mercredi 26 juin 2013
Statut
Membre
Dernière intervention
11 juillet 2013
3 juil. 2013 à 20:02
3 juil. 2013 à 20:02
Haaaaa ! Je n'arrive pas à faire les flèches...
donc en faisant abstraction des residus de ces dernières, pour la condition
-"L'utilisateur a-t'il rentré un pseudomyme ?" la flèche irait à "l'utilisateur rentre un pseudonyme"
-"La classe rentrée par l'utilisateur est-elle valide ?" la flèche irait à "l'utilisateur rentre sa classe"
-"Autre joueur ?" la flèche irait à "message de bienvenue +message pour le pseudonyme "
P.S. : "message pour le pseudonyme/la classe" signifie "message demandant de rentrer le pseudonyme/la classe".
donc en faisant abstraction des residus de ces dernières, pour la condition
-"L'utilisateur a-t'il rentré un pseudomyme ?" la flèche irait à "l'utilisateur rentre un pseudonyme"
-"La classe rentrée par l'utilisateur est-elle valide ?" la flèche irait à "l'utilisateur rentre sa classe"
-"Autre joueur ?" la flèche irait à "message de bienvenue +message pour le pseudonyme "
P.S. : "message pour le pseudonyme/la classe" signifie "message demandant de rentrer le pseudonyme/la classe".
[Dal]
Messages postés
6203
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
29 janvier 2025
1 099
3 juil. 2013 à 20:10
3 juil. 2013 à 20:10
OK,
et à quoi sert "continuerPseudoClasse" ?
Pourquoi compares-tu la saisie du "pseudo" saisit à "continuerPseudoClasse" ?
Dal
et à quoi sert "continuerPseudoClasse" ?
Pourquoi compares-tu la saisie du "pseudo" saisit à "continuerPseudoClasse" ?
Dal
[Dal]
Messages postés
6203
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
29 janvier 2025
1 099
4 juil. 2013 à 12:24
4 juil. 2013 à 12:24
Salut tinkilechat,
Alors voilà un code fonctionnel, dans lequel j'ai mis les différentes recommandations qui t'ont été faites.
J'ai ajouté d'autres changements, car il y avait beaucoup de code redondant dans ton source, avec tous les if / else, et une gestion qui risque de s'avérer difficile si tu dois changer un jour le nom d'une classe de personnage, ou ajouter des caractéristiques.
C'est une proposition de code. Il y a différentes techniques non précédemment mentionnées, qui sont expliquées dans les commentaires.
Etudie bien le code, et pose des questions si tu ne comprends pas.
Dal
Alors voilà un code fonctionnel, dans lequel j'ai mis les différentes recommandations qui t'ont été faites.
J'ai ajouté d'autres changements, car il y avait beaucoup de code redondant dans ton source, avec tous les if / else, et une gestion qui risque de s'avérer difficile si tu dois changer un jour le nom d'une classe de personnage, ou ajouter des caractéristiques.
C'est une proposition de code. Il y a différentes techniques non précédemment mentionnées, qui sont expliquées dans les commentaires.
Etudie bien le code, et pose des questions si tu ne comprends pas.
#include <stdio.h> #include <string.h> /* dans le .h */ /* définitions */ #define MAX_ST_LEN_PLAYER 50 /* taille max des chaînes Player */ #define MAX_ST_LEN 255 /* taille max des autres chaînes */ #define MAX_JOUEURS 5 /* taille max du tableau de Player */ /* énumérations */ typedef enum { GUERRIER, PALADIN, MAGE, ARCHER, VOLEUR, IDCLASSETYPECOUNT } IDClasseType; /* typedef enum permet de créer un type entier, * GUERRIER = 0, PALADIN = 1, etc. * le dernier IDCLASSETYPECOUNT est ajouté pour * savoir combien d'éléments existent dans cet enum */ /* structure de données définissant un * joueur */ typedef struct Player Player; struct Player { char pseudo[MAX_ST_LEN_PLAYER]; IDClasseType id_classe; /* pour la classe de personnage, il est mieux * de stocker un numéro identifiant la classe, * plutôt qu'une chaîne * cela va permettre de rattacher à ce numéro * différentes caractéristiques attachées à * une classe, et de les faire évoluer plus * facilemement */ int niveau; }; /* structure de données définissant une * classe de personnage */ typedef struct ClassePerso ClassePerso; struct ClassePerso { char nom[MAX_ST_LEN]; char salutation[MAX_ST_LEN]; /* la structure peut être étendue avec * les caractéristiques propres à chaque * classe de personnage, points de vie, etc. */ }; /* fin du .h */ int main(int argc, char *argv[]) { int numeroJoueur = 0; int continuer = 0; char pseudo[MAX_ST_LEN_PLAYER], classe[MAX_ST_LEN_PLAYER]; IDClasseType id_classe_choisie; /* on crée un tableau de Player * pour conserver les données des * différents joueurs */ Player joueur[MAX_JOUEURS]; /* on crée et on initialise le tableau * des ClassesPerso */ ClassePerso classes[] = { [GUERRIER] { "guerrier", "Vous etes desormais un noble et valeureux guerrier !" }, [PALADIN] { "paladin", "Allez dans l'honneur (achievement get : to quote Wow) !" }, [MAGE] { "mage", "Hooo, vous maitrisez les arcanes ?" }, [ARCHER] { "archer", "Que vos fleches transpercent nos ennemis !" }, [VOLEUR] { "voleur", "Honte a vous, brigand !" } }; /* on informe du nombre de joueurs max */ printf("Interface de création de joueurs (%d joueurs max)\n\n", MAX_JOUEURS); do { joueur[numeroJoueur].niveau = 1; do { printf("Nouveau joueur numero %d, veuillez " "entrer votre pseudonyme et " "choisir votre classe\n\nVotre pseudonyme : ", numeroJoueur + 1); pseudo[0] = '\0'; /* en mettant \0 en première position, on "vide" la chaîne */ scanf("%49[^\n]", pseudo); char c; while ((c = getchar()) != '\n' && c != EOF) /* purger stdin */; strncpy(joueur[numeroJoueur].pseudo, pseudo, MAX_ST_LEN_PLAYER - 1); /* si l'utilisateur a juste saisit entrée, * pseudo est toujours vide, et on boucle */ } while (pseudo[0] == '\0'); printf("\n\nBienvenue %s\n\n" "Veuillez saisir votre classe (choix possibles : ", pseudo); /* on énumère les choix possibles * la structure de données permet * de séparer les données du code */ { /* cette accolade est volontaire * elle me permet d'utiliser des variables * jetables, dont la durée de vie est limitée * au bloc, ici "n", que j'aime bien */ int n; for (n = 0; n < IDCLASSETYPECOUNT; n++) { printf(classes[n].nom); if (n != IDCLASSETYPECOUNT - 1) printf(", "); } printf(")\n\n"); } printf("Votre classe : "); /* on fait un while (1) pour toujours boucler, et on utilise * break pour sortir de la boucle */ while (1) { classe[0] = '\0'; scanf("%49[^\n]", classe); char c; while ((c = getchar()) != '\n' && c != EOF) /* purger stdin */; /* on utilise cette variable comme un booléen * pour savoir si la classe entrée est valide */ int is_class_ok = 0; /* initialisée à 0 (faux) */ /* on énumère les types de classes de * personnages pour vérifier la saisie, * et on salue */ { /* c'est plus concis, et il n'y a pas * de code redondant : un seul "if" */ int n; for (n = 0; n < IDCLASSETYPECOUNT; n++) { if (strcmp(classe, classes[n].nom) == 0) { printf("\n\n%s\n\n", classes[n].salutation); is_class_ok = 1; id_classe_choisie = n; } } } if (is_class_ok) { /* si on a une saisie correcte, on conserve la saisie * dans le tableau et on sort de la boucle while */ joueur[numeroJoueur].id_classe = id_classe_choisie; break; } else { printf("\n\nVeuillez entrer un nom " "de classe valide.\n\n"); } /* si on arrive ici, cela signifie que l'entrée est * inconnue, et on boucle */ } /* fin boucle while (1) */ numeroJoueur++; if (numeroJoueur < MAX_JOUEURS) { /* il reste de la place pour des joueurs * additionnels, on demande s'il faut en créer * plus */ printf("Nouveau joueur ?\n\n 0 = non\n 1 = oui\n"); scanf("%d", &continuer); { char c; while ((c = getchar()) != '\n' && c != EOF) /* purger stdin */; } } else { /* on a atteint la limite, on en informe * l'utilisateur et on ne continue pas */ printf("Nombre maximal de joueurs saisit\n"); continuer = 0; } } while (continuer); /* faire quelque chose avec le tableau de Player saisi */ printf("Vous avez saisi %d joueurs\n", numeroJoueur); { int n; for (n = 0; n < numeroJoueur; n++) { printf("Joueur %d - %s - %s\n", n + 1, joueur[n].pseudo, classes[joueur[n].id_classe].nom); } } return 0; }
Dal
tinkilechat
Messages postés
15
Date d'inscription
mercredi 26 juin 2013
Statut
Membre
Dernière intervention
11 juillet 2013
4 juil. 2013 à 15:22
4 juil. 2013 à 15:22
Il me faudra bien deux journées entières pour étudier tout cela en détail !
Il y a trop de choses, trop de notions qui me sont encore étrangères... C'est pire que des maths pour moi !
Merci quand même pour autant de préoccupation à mon sujet !
Il y a trop de choses, trop de notions qui me sont encore étrangères... C'est pire que des maths pour moi !
Merci quand même pour autant de préoccupation à mon sujet !
[Dal]
Messages postés
6203
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
29 janvier 2025
1 099
4 juil. 2013 à 17:07
4 juil. 2013 à 17:07
Je ne crois pas que la compréhension de mon code ne soit pas à ta portée, si tu es rendu là où tu dis du cours du zéro.
Sinon, j'ai répondu à ta question concernant ton dernier code, où tu demandais :
"le problème n°1 est résolut mais il y a toujours le 2ème : quoi que l'on rentre dans la chaîne classe[50], elle ne sera jamais égale aux chaînes de test (strcmp (pseudo, chaînedetest) == 0) tels que guerrier[], mage[], archer[] (Et ce même si ces dernières ont la même taille.)"
ce à quoi j'ai répondu :
"pour tes comparaisons, c'est normal que cela ne donne rien, car tu compares "pseudo" à tes chaînes.... alors que ce que tu veux comparer c'est, je pense, ce que l'utilisateur a saisit dans "classe"."
donc, selon mes indications, c'est
Dal
Sinon, j'ai répondu à ta question concernant ton dernier code, où tu demandais :
"le problème n°1 est résolut mais il y a toujours le 2ème : quoi que l'on rentre dans la chaîne classe[50], elle ne sera jamais égale aux chaînes de test (strcmp (pseudo, chaînedetest) == 0) tels que guerrier[], mage[], archer[] (Et ce même si ces dernières ont la même taille.)"
ce à quoi j'ai répondu :
"pour tes comparaisons, c'est normal que cela ne donne rien, car tu compares "pseudo" à tes chaînes.... alors que ce que tu veux comparer c'est, je pense, ce que l'utilisateur a saisit dans "classe"."
donc, selon mes indications, c'est
strcmp (classe, chaînedetest) == 0que tu voudrais faire, pour résoudre ton problème immédiat dans ton dernier code.
Dal
tinkilechat
Messages postés
15
Date d'inscription
mercredi 26 juin 2013
Statut
Membre
Dernière intervention
11 juillet 2013
10 juil. 2013 à 18:57
10 juil. 2013 à 18:57
Finalement, je me suis ENFIN mis à étudier ce long code !
Voici mes remarques et mes incompréhensions :
Pour le fichier.h :
*Si je comprend bien, la structure Player est sensée elle même contenir une structure ClassePerso contenant le nom, une chaîne de caractère vierge pour le message de bienvenue ainsi que les éventuelles caractéristiques et autres description ?
Pour le main.c :
*[^\n] (<== c'est quoi ça ?) : Pourquoi avoir mis un accent circonflexe avant '\n' et puis d'ailleurs, pourquoi avoir mis ça entre crochets après %49 ?
Par contre, je comprends que %49 indique à la fonction scanf de rentrer le 50ème caractère dans pseudo[MAX_ST_LEN_PLAYER] (c'est bien ça ?). Du coup, [^\n] oblige à rentrer le caractère \n en pressant la touche "Entrée" dans le 50ème et dernier caractère de pseudo, non ?
*c = getchar : Je viens de réaliser que je ne connait pas cette formule (Ou bien la mémoire m'a fait défaut lorsque que je l'ai vue)! Ayant poursuivi sur le chapitre "Lire et écrire dans des fichiers", je croyais avoir vu cette fonction, mais la fonction que j'ai apprise est fgetc et non getchar... Du coup je ne sais ni ce qu'elle est censée effectuer, ni son prototype.
Voici mes remarques et mes incompréhensions :
Pour le fichier.h :
*Si je comprend bien, la structure Player est sensée elle même contenir une structure ClassePerso contenant le nom, une chaîne de caractère vierge pour le message de bienvenue ainsi que les éventuelles caractéristiques et autres description ?
Pour le main.c :
*[^\n] (<== c'est quoi ça ?) : Pourquoi avoir mis un accent circonflexe avant '\n' et puis d'ailleurs, pourquoi avoir mis ça entre crochets après %49 ?
Par contre, je comprends que %49 indique à la fonction scanf de rentrer le 50ème caractère dans pseudo[MAX_ST_LEN_PLAYER] (c'est bien ça ?). Du coup, [^\n] oblige à rentrer le caractère \n en pressant la touche "Entrée" dans le 50ème et dernier caractère de pseudo, non ?
*c = getchar : Je viens de réaliser que je ne connait pas cette formule (Ou bien la mémoire m'a fait défaut lorsque que je l'ai vue)! Ayant poursuivi sur le chapitre "Lire et écrire dans des fichiers", je croyais avoir vu cette fonction, mais la fonction que j'ai apprise est fgetc et non getchar... Du coup je ne sais ni ce qu'elle est censée effectuer, ni son prototype.
[Dal]
Messages postés
6203
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
29 janvier 2025
1 099
Modifié par [Dal] le 10/07/2013 à 20:31
Modifié par [Dal] le 10/07/2013 à 20:31
Salut tinkilechat,
Si je comprend bien, la structure Player est sensée elle même contenir une structure ClassePerso contenant le nom, une chaîne de caractère vierge pour le message de bienvenue ainsi que les éventuelles caractéristiques et autres description ?
Non, ce sont deux structures différentes, pour accueillir deux types de données différentes :
- Player : pour faire un tableau de joueurs
- ClassePerso : pour stocker les caractéristiques d'une classe de personnage (là aussi, sous la forme d'un tableau)
[^\n] (<== c'est quoi ça ?) : Pourquoi avoir mis un accent circonflexe avant '\n' et puis d'ailleurs, pourquoi avoir mis ça entre crochets après %49 ?
Les crochets permettent de spécifier une classe de caractères acceptables. Le ^ signifie ici la négation, et donc signifie que tous les caractères saufs ceux mentionnés entre crochets sont acceptables.
Par contre, je comprends que %49 indique à la fonction scanf de rentrer le 50ème caractère dans pseudo[MAX_ST_LEN_PLAYER] (c'est bien ça ?).
Non, cela signifie que la longueur en caractères que scanf doit prendre en compte est limitée à 49.
Du coup, [^\n] oblige à rentrer le caractère \n en pressant la touche "Entrée" dans le 50ème et dernier caractère de pseudo, non ?
Non. Entrée est de toutes façons nécessaire dans le fonctionnement normal d'une console pour que les données soient envoyées au programme.
L'ensemble signifie, comme déjà indiqué : prend tout ce qu'il y a dans le flux stdin, dans la limite de 49 caractères, et je ne veux pas de '\n' (donc : si tu vois un '\n' avant d'arriver au 49ème caractère, tu t'arrêtes au dernier caractère qui n'est pas un '\n').
scanf est décrite là :
http://www.cplusplus.com/reference/cstdio/scanf/
c = getchar : Je viens de réaliser que je ne connait pas
getchar prend un caractère dans le flux stdin, s'il n'en reste plus, elle renvoie EOF.
http://www.cplusplus.com/reference/cstdio/getchar/
Si tu as compris tout le reste, félicitations !
Le support de cours dont tu disposes n'est pas toute la source d'information pertinente sur le langage que tu apprends. Il faut te reporter à une source de référence sur le langage, qui peut être : le standard du C, un manuel, sous Linux les pages de manuel, ou un site comportant une information de référence.
Ces pages dont je t'envoie les liens sont les pages qui apparaissent en premier lorsqu'on tape "scanf" ou "getchar" sur Google.
J'aime bien ce site, qui est une référence de bonne qualité sur le langage C (et C++ en fait).
A partir de http://www.cplusplus.com/reference/clibrary/ tu disposes de liens vers les différentes parties de la bibliothèque standard du C, puis vers les instructions accessibles par chaque entête standard, avec leurs prototypes et fonctionnement et des exemples.
Je te conseille, lorsque tu rencontres une nouvelle fonction standard, d'avoir une référence fiable à portée de la main, pour avoir une vue complète. Même s'il y a des choses qui t'échappent au début, tu pourras rechercher, dans la référence, la confirmation de ce que tu lis dans le cours.
Dal
Si je comprend bien, la structure Player est sensée elle même contenir une structure ClassePerso contenant le nom, une chaîne de caractère vierge pour le message de bienvenue ainsi que les éventuelles caractéristiques et autres description ?
Non, ce sont deux structures différentes, pour accueillir deux types de données différentes :
- Player : pour faire un tableau de joueurs
- ClassePerso : pour stocker les caractéristiques d'une classe de personnage (là aussi, sous la forme d'un tableau)
[^\n] (<== c'est quoi ça ?) : Pourquoi avoir mis un accent circonflexe avant '\n' et puis d'ailleurs, pourquoi avoir mis ça entre crochets après %49 ?
Les crochets permettent de spécifier une classe de caractères acceptables. Le ^ signifie ici la négation, et donc signifie que tous les caractères saufs ceux mentionnés entre crochets sont acceptables.
Par contre, je comprends que %49 indique à la fonction scanf de rentrer le 50ème caractère dans pseudo[MAX_ST_LEN_PLAYER] (c'est bien ça ?).
Non, cela signifie que la longueur en caractères que scanf doit prendre en compte est limitée à 49.
Du coup, [^\n] oblige à rentrer le caractère \n en pressant la touche "Entrée" dans le 50ème et dernier caractère de pseudo, non ?
Non. Entrée est de toutes façons nécessaire dans le fonctionnement normal d'une console pour que les données soient envoyées au programme.
L'ensemble signifie, comme déjà indiqué : prend tout ce qu'il y a dans le flux stdin, dans la limite de 49 caractères, et je ne veux pas de '\n' (donc : si tu vois un '\n' avant d'arriver au 49ème caractère, tu t'arrêtes au dernier caractère qui n'est pas un '\n').
scanf est décrite là :
http://www.cplusplus.com/reference/cstdio/scanf/
c = getchar : Je viens de réaliser que je ne connait pas
getchar prend un caractère dans le flux stdin, s'il n'en reste plus, elle renvoie EOF.
http://www.cplusplus.com/reference/cstdio/getchar/
Si tu as compris tout le reste, félicitations !
Le support de cours dont tu disposes n'est pas toute la source d'information pertinente sur le langage que tu apprends. Il faut te reporter à une source de référence sur le langage, qui peut être : le standard du C, un manuel, sous Linux les pages de manuel, ou un site comportant une information de référence.
Ces pages dont je t'envoie les liens sont les pages qui apparaissent en premier lorsqu'on tape "scanf" ou "getchar" sur Google.
J'aime bien ce site, qui est une référence de bonne qualité sur le langage C (et C++ en fait).
A partir de http://www.cplusplus.com/reference/clibrary/ tu disposes de liens vers les différentes parties de la bibliothèque standard du C, puis vers les instructions accessibles par chaque entête standard, avec leurs prototypes et fonctionnement et des exemples.
Je te conseille, lorsque tu rencontres une nouvelle fonction standard, d'avoir une référence fiable à portée de la main, pour avoir une vue complète. Même s'il y a des choses qui t'échappent au début, tu pourras rechercher, dans la référence, la confirmation de ce que tu lis dans le cours.
Dal
fiddy
Messages postés
11069
Date d'inscription
samedi 5 mai 2007
Statut
Contributeur
Dernière intervention
23 avril 2022
1 844
10 juil. 2013 à 21:16
10 juil. 2013 à 21:16
@[Dal],
getchar prend un caractère dans le flux stdin, s'il n'en reste plus, elle renvoie EOF.
Nope. S'il n'en reste plus, il se "met en écoute" sur l'entrée standard.
getchar prend un caractère dans le flux stdin, s'il n'en reste plus, elle renvoie EOF.
Nope. S'il n'en reste plus, il se "met en écoute" sur l'entrée standard.
26 juin 2013 à 19:37
Modifié par [Dal] le 26/06/2013 à 22:55
C'est très juste, effectivement, si on n'oublie pas d'ajouter les spécificateurs de taille aux spécificateurs de formats. Mais comme "%49s" va s'arrêter au premier espace ou tabulation venu, ce n'est pas si adapté pour récupérer une saisie arbitraire d'un utilisateur telle que "Tinki le Chat", où scanf s'arrêtera à "Tinki", alors que l'utilisateur a tapé "Tinki le Chat" et qu'il est bien en dessous des 50 octets alloués.
Il me semble que cela n'arrive pas avec le code suivant.
Dal
26 juin 2013 à 23:31
Pas d'accord. Il faut juste connaître le format ;-). Par exemple :
Et, il ne faut pas oublier de flusher ensuite le buffer clavier.
27 juin 2013 à 02:12
27 juin 2013 à 09:33
scanf est très complexe, et il ne faut pas se rater en l'utilisant.
Dal