Souci avec fscanf en c

Fermé
Arfash - 29 oct. 2009 à 20:21
 Arfash - 2 nov. 2009 à 16:41
Bonjour,
Je dois faire un programme qui gère des fiches d'informations sur des personnes stockées dans un fichier texte, qui se présente de la manière suivante :

nom prenom sexe(0 ou 1) age goutmusical1 goutmusical2 goutmusical3 sport1 sport2 sport3 loisir1 loisir2 loisir3

et on passe à la ligne pour la fiche suivante.

Lors de l'execution du programme je veux une option pour ajouter une fiche, et tout se passe bien jusqu'au moment d'entrer au clavier les gouts musicaux, il me demande 4 entrées au lieu de 3 et du coup tout est décalé.

Bon mes explications ne sont pas très claires donc je vous donne mon code source ci-dessous. Le problème se passe lors de l'appel de la fonction ajoutefiche quand cette dernière appelle scanmusic(a,stdin).

J'ai essayé de faire avec des scanf, et des fgets mais à chaque fois il y avait un décalage, donc je vois vraiment pas d'ou ça viens, si quelqu'un peut m'aider ... :)

le code source :

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

#define BORNE 3
#define TAILLE 20

typedef struct fiche *pfiche;
typedef struct fiche fiche;
struct fiche {
  char *nom;
  char *prenom;
  int sexe;
  int age;
  char* music[BORNE];
  char* sport[BORNE];
  char* loisirs[BORNE];
  pfiche suivante;
};


void scanmusic(pfiche a, FILE* flot) {
    int i;
    for (i=0;i<BORNE;i++) {
        a->music[i]=(char*)malloc(TAILLE*sizeof(char));
        fscanf(flot,"%s ", a->music[i]);
            }
}


void scansport(pfiche a, FILE* flot) {
    int i;
    for (i=0;i<BORNE;i++) {
        a->sport[i]=(char*)malloc(TAILLE*sizeof(char));
        fscanf(flot,"%s ", a->sport[i]);
    }
}

void scanloisirs(pfiche a, FILE* flot) {
    int i;
    for (i=0;i<BORNE;i++) {
        a->loisirs[i]=(char*)malloc(TAILLE*sizeof(char));
        fscanf(flot,"%s ", a->loisirs[i]);
    }
}


pfiche getliste (FILE* flot) {
  int c = fgetc(flot);
  if(c==EOF){return NULL;}
  else{ungetc(c,flot);}
  pfiche a = (pfiche)malloc(sizeof(fiche));
  a->nom=(char*)malloc(TAILLE*sizeof(char));
  a->prenom=(char*)malloc(TAILLE*sizeof(char));
  fscanf(flot,"%s %s %d %d\n", a->nom, a->prenom, &a->sexe, &a->age);
  scanmusic(a,flot);
  scansport(a,flot);
  scanloisirs(a,flot);
  a->suivante = getliste(flot);
  return a;
  }

int saveliste (pfiche racine, FILE* flot) {
    if (racine==NULL) {return 0;}
    int i;
    fprintf(flot,"%s %s %d %d ", racine->nom, racine->prenom, racine->sexe, racine->age);
    free(racine->nom);
    free(racine->prenom);
    for (i=0;i<BORNE;i++) {
    fprintf(flot,"%s ", racine->music[i]);
    free(racine->music[i]);
    }
    for (i=0;i<BORNE;i++) {
    fprintf(flot,"%s ", racine->sport[i]);
    free(racine->sport[i]);
    }
    for (i=0;i<BORNE;i++) {
    fprintf(flot,"%s ", racine->loisirs[i]);
    free(racine->loisirs[i]);
    }
    if ((racine->suivante)!=NULL) {fprintf(flot,"\n");}
    saveliste(racine->suivante,flot);
    free(racine);
}

int afficheliste(pfiche racine) {
    char* s[]={"masculin","feminin"};
    if (racine==NULL) {
        printf("\n \n");
        return 0;
        }
    printf("\n \n%s %s\nage : %d ans\nsexe : %s\n", racine->prenom, racine->nom, racine->age, s[racine->sexe]);
    printf("Gouts musicaux : ");
    int i;
    for (i=0;i<BORNE;i++){
        if(strcmp(racine->music[i],"null")) {printf("%s ",racine->music[i]);}
    }
    printf("\nSports pratiques : ");
    for (i=0;i<BORNE;i++){
        if(strcmp(racine->sport[i],"null")) {printf("%s ",racine->sport[i]);}
    }
    printf("\nLoisirs : ");
    for (i=0;i<BORNE;i++){
        if(strcmp(racine->loisirs[i],"null")) {printf("%s ",racine->loisirs[i]);}
    }
    afficheliste(racine->suivante);
}

pfiche ajoutefiche(FILE* flot, pfiche racine) {
  pfiche a = (pfiche)malloc(sizeof(fiche));
  a->nom=(char*)malloc(TAILLE*sizeof(char));
  a->prenom=(char*)malloc(TAILLE*sizeof(char));
  printf("\nnom ?");
  scanf("%s", a->nom);
  printf("\nprenom ?");
  scanf("%s", a->prenom);
  printf("\nsexe ? (0=homme ; 1=femme)");
  scanf("%d", &a->sexe);
  printf("\nage ?");
  scanf("%d", &a->age);
  printf("\nGouts musicaux : \n(%d maximum, pas plus de %d caracteres chacun)", BORNE, TAILLE);
  scanmusic(a,stdin);
  printf("\nSports pratiques : \n(%d maximum, pas plus de %d caracteres chacun)", BORNE, TAILLE);
  scansport(a,stdin);
  printf("\nLoisirs : \n(%d maximum, pas plus de %d caracteres chacun)", BORNE, TAILLE);
  scanloisirs(a,stdin);
  a->suivante=racine;
  return a;
}

int main(int argc, char *argv[]){
  if (argc!=2)
    {
      printf("\nErreur : nombre invalide d'arguments");
      printf("\nUsage: %s fichier.txt\n",argv[0]);
      return(1);
    }
  char *fichier = argv[1];
  FILE* flot;
  if((flot=fopen(fichier,"r"))==NULL)
    {
      fprintf(stderr,"Impossible d'ouvrir %s en lecture.\n", fichier);
      return(1);
    }
  pfiche racine = getliste(flot);
  fclose(flot);


  int stop = 0;
  while (stop==0) {
      printf("\n 1.Afficher\n 2.Ajouter\n 3.Retirer\n 4.Quitter\n");
      int choix;
      scanf("%d", &choix);
      if ((choix==1)||(choix==2)||(choix==3)||(choix==4)){
          if (choix==4) {stop=1;}
          if (choix==3) {stop=0;}
          if (choix==2) {racine=ajoutefiche(flot,racine);}
          if (choix==1) {afficheliste(racine);}
      }
      else {printf("\n >> erreur de saisie ! <<\n");}
  }


  if((flot=fopen(fichier,"w"))==NULL)
    {
      fprintf(stderr,"Impossible d'ouvrir %s en écriture.\n", fichier);
      return(1);
    }
    saveliste(racine,flot);
    fclose(flot);

  return 0;
}

3 réponses

pacorabanix
29 oct. 2009 à 22:11
et le problème de décalage, est-ce qu'il recommence après encore (avec les autres choses comme loisir ?) ou seulement pour la musique ?

PS : tu n'as pas besoin de caster tes malloc il me semble...
1
j'ai fait une modification de scanmusic de la façon suivante :

void scanmusic(pfiche a, FILE* flot) {
    int i;
    for (i=0;i<BORNE;i++) {
        a->music[i]=(char*)malloc(TAILLE*sizeof(char));
        printf("%d \n", i);
        fscanf(flot,"%s ", a->music[i]);
            }
}


On a donc un printf qui affiche i dans la boucle pour qu'on puisse voir ou on en est rendu.

le programme me donne ceci :

[...]

Gouts musicaux : (3 maximum, pas plus de 20 caracteres chacun)0
gout1
gout2
1
gout3
2
gout4

Sports pratiques [...]

et là je pige pas, mais alors vraiment pas, pourquoi dans le même tour de boucle il demande 2 fois une entrée au clavier...


Sinon pour le cast des malloc j'en avais pas entendu parler avant donc j'ai fait quelques recherches (on nous avait appris à faire comme ça en cours), et apparemment y'aurait pas besoin mais pour une raison quelconque codeblocks ne veut pas compiler si je le vire (invalid pointer conversion quelquechose comme ça).
1
Bon en fait j'ai carrément mis 2 printf :

void scanmusic(pfiche a, FILE* flot) {
    int i;
    for (i=0;i<BORNE;i++) {
        a->music[i]=(char*)malloc(TAILLE*sizeof(char));
        printf("%d \n",i);
        fscanf(flot,"%s ", a->music[i]);
        printf("%d \n",i);
            }
}


on a maintenant :

Gouts musicaux : (3 maximum, pas plus de 20 caracteres chacun)0
gout1
gout2
0
1
gout3
1
2
gout4
2

Donc c'est un seul fscanf qui réclame deux entrées, c'est étrange non ?
0
Arfash > Arfash
2 nov. 2009 à 16:41
Bon ben le problème est finalement résolu !

ça venait de l'espace après le %s dans le fscanf, qui servait à lire dans le fichier à la base mais qui passait mal sur l'entrée clavier, du coup faut modifier un peu la fonction et ajouter aussi la même chose sur les deux autres (sport et loisirs) :

void scanmusic(pfiche a, FILE* flot) {
    int i,c;
    for (i=0;i<BORNE;i++) {
        a->music[i]=(char*)malloc(TAILLE*sizeof(char));
        fscanf(flot,"%s", a->music[i]);
        if(flot!=stdin){
            if((c=fgetc(flot))==EOF){
                ungetc(c,flot);
            }
        }
    }
}
0
En fait après avoir affiché qu'on doive rentrer les gouts musicaux il nous fais rentrer 4 chaines au lieu de 3, ensuite 3 pour les sports et 3 pour les loisirs, mais le hic c'est que le dernier loisir compte pour le scanf du menu, et que dans le fichier le quatrieme gout musical est en fait le premier sport et le 3eme sport le 1er loisir.

Je me doute bien que le probleme doit être lié au buffer, mais j'ai beau potasser mes cours sur le sujet je ne vois pas ce qui fait qu'il me fais ça.

Pour apporter un peu plus de précision par rapport à l'endroit ou ça bug : j'avais testé en mettant un printf("%d",i) dans la boucle for de la fonction scanmusic (entre le malloc et le fscanf) : et à l'execution il ne me met pas de 0 avant le premier scan du gout musical, ensuite il en met un pour le second, un 1 pour le 3eme et un 2 pour le 4eme. On a donc bien une demande d'entrée clavier en trop et je ne vois pas d'ou elle peut venir.
0