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
Bonjour, j'apprend actuellement le C89 grâce au SiteduZero depuis quelque mois. Etant rendu à la motiée de la partie 2 (les technique avancées du langage C), je me suis atteler à effectuer un exercice sur les structure. Bien que vous remarquerez l'absence de toute utilisation de structure dans mon code, je comptais en utiliser pour stocker les contenus de pseudo[50], de classe[50] et de niveau (variable absente mais que je comptais rajouter à l'ensemble et initialiser à 1).

Mon problème réside dans le fait que (comme le titre l'indique) les deux fonctions scanf s'exécutent deux fois et la seconde (celle du choix de la classe) affiche toujours le else quelque soit la rentrée de l'utilisateur.

Je vous remercie à l'avance de vos réponses et vous souhaite une bonne journée !

P.S. Oui, je sais, j'ai omis de faire une boucle pour le choix de la classe, du coup, le programme ne propose pas de rentrer à nouveau une chaîne de caractères dans classe[] après avoir dit "Veuillez rentrer un mon de classe valide."...

Voici le code du main.c :

#include <stdio.h>
#include <stdlib.h>
#include "fichier.h"

int main(int argc, char *argv [])
{
int numeroJoueur = 1;
int continuer = 0;
char pseudo [50];
char classe[50];
char continuerPseudoClasse[50];

do
{
do

printf("Nouveau joueur numero %d, veuillez rentrez votre pseudonyme et choisissez votre \nclasse\nVotre pseudonyme : ", numeroJoueur);
scanf("%s\n\n", pseudo);
} while (pseudo[50] == continuerPseudoClasse[50]);

printf("Bienvenue %s\n Veulliez selectionner votre classe : \nguerrier\n paladin\n mage\n archer\n voleur\n\n", pseudo);

scanf ("%s\n\n", classe);

if (classe == "guerrier")
{
printf ("Vous etes desormais un noble et valeureux guerrier !");
}

else if (classe == "paladin")
{
printf ("Allez dans l'honneur (achievement get : to quote Wow) !");
}

else if (classe == "mage")
{
printf ("Hooo, vous maitrisez les arcanes !");
}

else if (classe == "archer")
{
printf ("Que vos fleches transpercent nos ennemis !");
}

else if (classe == "voleur")
{
printf ("Honte a vous, brigand !");
}

else
{
printf ("Veuillez entrer un nom de classe valide.\n\n");
}



numeroJoueur ++;

printf ("Nouveau joueur ?\n\n 0 = non\n 1 = oui");
scanf ("%d", &continuer);

}while (continuer);




return 0;
}

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
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'
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 844
26 juin 2013 à 19:37
Avec scanf aussi on peut maitriser la taille :-p
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 26/06/2013 à 22:55
Bonsoir fiddy,

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.

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
   char pseudo[50];
    printf("Veuillez entrer votre pseudo "
            "(50 caractères max) : ");
    if (scanf("%49s", pseudo))
    {
        printf("J'ai récupéré : [%s]\n", pseudo);
    }
    return 0;
}


Il me semble que cela n'arrive pas avec le code suivant.

#include <stdio.h>
#include <string.h>

int main(void)
{
    char pseudo[50];
    char *p;
    printf("Veuillez entrer votre pseudo "
            "(50 caractères max) : ");
    if (fgets(pseudo, 50, stdin) != NULL)
    {
        if ((p = strchr(pseudo, '\n')) != NULL)
          *p = '\0';
        printf("J'ai récupéré : [%s]\n", pseudo);
    }
    return 0;
}


Dal
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 844
26 juin 2013 à 23:31
C'est très juste, effectivement, si on n'oublie pas d'ajouter les spécificateurs de taille aux spécificateurs de formats.
Pas d'accord. Il faut juste connaître le format ;-). Par exemple :
char ch[50]={0};

if(scanf("%49[^\n]",ch) == 1) {
     /*saisie ok*/
}

Et, il ne faut pas oublier de flusher ensuite le buffer clavier.
0
nar6du14 Messages postés 459 Date d'inscription dimanche 27 décembre 2009 Statut Membre Dernière intervention 7 décembre 2013 64
27 juin 2013 à 02:12
c'est le code le plus brouillon que j'ai jamais vu, il faut identer ton code, bien le structure, toujours initialiser les pointeurs à NULL etc
0
[Dal] Messages postés 6203 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 29 janvier 2025 1 099
27 juin 2013 à 09:33
fiddy : merci de cet exemple, c'est très malin. J'avoue ne l'avoir pas vu souvent dans du code, mais cela marche bien. N'est-ce pas du C99 ?

scanf est très complexe, et il ne faut pas se rater en l'utilisant.


Dal
0
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
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
0
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
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 { ... }.
while (strcmp(pseudo, guerrier) != 0 || strcmp(pseudo, paladin) != 0 || strcmp(pseudo, mage) != 0 || strcmp(pseudo, archer) != 0 || strcmp(pseudo, voleur) != 0)
{
    Player joueur;
do
>
0
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
Ok ! Encore une fois, merci fiddy ! :3
0
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
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;
}
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
Salut,

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
0
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
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
0
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
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
0
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
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".
0
[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
OK,

et à quoi sert "continuerPseudoClasse" ?

Pourquoi compares-tu la saisie du "pseudo" saisit à "continuerPseudoClasse" ?


Dal
0
[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
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.

#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
0
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
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 !
0
[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
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

strcmp (classe, chaînedetest) == 0
que tu voudrais faire, pour résoudre ton problème immédiat dans ton dernier code.


Dal
0
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
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.
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 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
0
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
@[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.
0