(il me semble que tu avais mis des points virgule pour séparer jour mois annee pas des slash / ? J'ai donc mis des points virgule dans le fscanf.
Il faudrait aussi récupérer la valeur retournée par fscanf() et la comparer au nombre de valeurs dans les spécificateurs (ici 7) pour vérifier que son exécution a bien permis de récupérer les valeurs attendues (et décider quoi faire si ce n'est pas le cas).
Sinon, personnellement, je préfère récupérer du texte pour ces types de données (mais la struct du PO n'est pas prévue pour) et utiliser strtok() pour récupérer les données selon le séparateur utilisé par le format csv.
J'ai déjà proposé strtok avec fgets mais ce n'est peutêtre pas évident pour le PO. Ensuite, si on veut garder des données numériques dans la structure, il faut utiliser sscanf() pour décoder (ou autre chose du style strtoi)
Le Tout est souvent plus grand que la somme de ses parties.
La bonne solution, ama, serait d'avoir une structure avec tous les champs, et d'utliser fwrite() et fread(), pour ne pas se faire emm.... par les ?scanf(). Mais c'est sans doute encore hors de portée du PO.
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
La bonne solution, ama, serait d'avoir une structure avec tous les champs, et d'utliser fwrite() et fread()
Pas simple pour sauvegarder en csv !
Exact, j'étais un peu plus à l'ouest en oubliant que le PO voulait un format csv. Sinon, l'idée de Pierrot avec fgets() et personnellement l'utilisation de strchr() me conviendrait bien.
- Edité par edgarjacobs 15 septembre 2021 à 20:33:02
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
Bon du coup j'étais parti pour créer un tableau contenant toutes les informations du fichier ( cela me facileterait l'affichage de la liste des étudiants, les recherches etc )
La fonction marche parfaitement. Sauf que une fois sur 2 le terminal de vscode n'interrompt pas le programme ! Comme s'il y avait une boucle infinie :/
J'ai l'impression que j'ai mal libéré la mémoire mais pour tout vous dire moi même je ne comprend pas trop mon code j'ai fait beaucoup de recherches et je me suis inspiré de ce que je voyais sans pour autant comprendre par exemple dans le cours de langage C d'open classroom, je n'ai pas rencontré de pointeur qui se déclarait de cette manière : char **monPointeur ( les deux étoiles je veux dire car quand j'en mettais un j'avais des erreurs et le code ne fonctionnait plus ) Et pourtant cette manière de déclarer revenait souvent dans mes recherches !
Donc si quelqu'un pouvait me l'expliquer et me dire (encore) une fois mon erreur :
Que veut dire *pointeur? C'est un pointeur vers quelque chose. Alors **pointeur est un pointeur vers ... un pointeur ... ou un tableau de pointeurs. C'est une façon de créer un tableau en mémoire dynamique avec malloc. Chaque entrée de ton tableau est elle-même un pointeur vers quelque chose. Cette chose est une chaîne de caractères. Que réserves-tu avec ceci? tableau = malloc(sizeof(char)*taille_bdd_etudiant); sizeof(char) est la dimension d'un caractère, ça vaut toujours 1. tableau est un pointeur vers un pointeur, ou comme j'ai dit, un tableau de pointeurs. Il faut écrire: tableau = malloc(sizeof(char *) * taille_bdd_etudiant); sizeof(char *) est la grandeur d'un pointeur vers une chaîne. Tu ne réservais pas assez de mémoire pour ton tableau de pointeurs. Tu détruisais de la mémoire au dela de ce qui t'avait été alloué. Quand tu étais chanceux, ça marchait. Sinon, ça détruisait des zones critiques. C'est ce qu'on appelle un comportement indéterminé, parce que c'est imprévisible. Maintenant, ton tableau contiendra une liste de chaînes. Ce n'est pas encore les structures que tu souhaiterais. C'est plus ou moins une image mémoire de ton fichier. Je suppose que c'est une première étape. Il faudra plus tard plutôt réserver l'espace pour des structures et les remplir.
Le Tout est souvent plus grand que la somme de ses parties.
Tout charger en mémoire est une solution, mais il serait probablement plus simple de te faire un tableau de structure que ton tableau de chaîne. Il en sera beaucoup plus simple d'en extraire les données !
Pendant qu'on y est, tu devrais revoir le découpage de ton code. Et choisir une fois pour toutes de nommer tes variables/fonctions dans une langue.
void recherche_etudiant()
{
printf("Recherche étudiant, 1 par nom, 2 par numero\n");
switch(choix(1,2)) {
case 1:
chercher_etudiant_par_nom();
break;
case 2:
chercher_etudiant_par_numero();
break;
}
}
/**
* demande un nombre entre premier et dernier.
* répète jusqu'à obtenir une réponse valide.
*/
int choix(int premier, int dernier);
- Edité par michelbillaud 16 septembre 2021 à 13:13:35
Normalement, à chaque entité de ton MPD doit correspondre une structure C, à chaque table doit correspondre un tableau (ou liste ou équivalent) de structure …
Chaque structure doit être accompagnée de fonctions de création, d'accès et modifications (au minimum) …
Edit: typos (avec énormément de retard, désolé).
- Edité par White Crow il y a moins de 5s
C'est pas pour rien que tu as un MPD, et comme je le disais ça évitera que tu construise une usine à gaz. Il ne faut jamais commencer à écrire du code avant d'avoir une ligne de conception claire.
Tu peux mieux me l'expliquer stp ? Avec les cours de système d'exploitation j'avais déjà eu l'occasion d'utiliser les [^] dans mes commandes donc est-ce la même chose ici ? Le scanf récupère tout sauf le ";" ? Pour quelle raisons alors le mien ne marchait pas ? ( le plus simple à savoir d'utiliser directement %d et %s avec les séparateurs )
J'ai créer une fonction rechercher_avec_numero que voici :
int rechercher_avec_numero(FILE *infEtudiant, int taille, etudiant *Etudiant, int numero)
{
int i = 0;
rewind (infEtudiant);
do
{
fscanf(infEtudiant,"%[^;];%[^;];%d/%d/%d;%d;%[^\n]\n", Etudiant->prenom, Etudiant->nom, &Etudiant->date_naissance.jour, &Etudiant->date_naissance.mois, &Etudiant->date_naissance.annee, &Etudiant->numero, Etudiant->email);
}
while (Etudiant->numero != numero && i < taille);
if (Etudiant->numero == numero)
{
return 1;
}
else
{
return 0;
}
}
Elle marche parfaitement et j'ai enfin les informations de l'étudiant si il est dans la bdd ( encore faut il que je comprenne le fscanf de rouloude )
Mais quand l'étudiant n'est pas trouvé, on dirait que la fonction part dans une boucle infinie
Voici le code qui l'appelle :
if (choix_Recherche == 1)
{
printf ("Rentrez le numero : ");
scanf ("%d",&num);
taille_etudiant = taille_bdd_etudiant(infEtudiant);
if (rechercher_avec_numero(infEtudiant,taille_etudiant,&Etudiant,num))
{
printf ("L'etudiant dont le numero est %d a ete trouve ! \nInformations : \n",num);
printf ("Nom : %s\nPrenom : %s\nDate de naissance : %d/%d/%d\nNumero : %d\nEmail : %s\n",Etudiant.prenom, Etudiant.nom, Etudiant.date_naissance.jour, Etudiant.date_naissance.mois, Etudiant.date_naissance.annee, Etudiant.numero, Etudiant.email);
}
else
{
printf ("L'etudiant avec le numero %d n'a pa ete trouve !\n",num);
printf ("Voulez vous reessayer avec l'email ?\n1. OUI\n2. NON");
scanf("%d",&continuer_avec_email);
while(continuer_avec_email < 1 || continuer_avec_email > 2)
{
printf ("Rentrez une valeur correcte SVP ! :");
scanf("%d",&continuer_avec_email);
}
}
On t'a expliqué que %s lit jusqu'au prochain "white space" comme espace ou '\n' [^\n] veut dire "tout sauf ce qui suit le ^ On doit bouffer le ';' en le mettant après cela. Tu n'as pas vraiment besoin d'un tableau de structures sauf si tu fais des comparaisons compliquées entre les étudiants. Une seule structure devrait suffire. Dans ta dernière fonction, tu ne testes pas le EOF
Le Tout est souvent plus grand que la somme de ses parties.
Le scanf : "%[^;];" lit jusqu'au point virgule compris et stocke le résultat sous forme de chaîne de caractère dans le tableau de char de destination en omettant le point virgule [^;]
Le scanf : "%[^;];" lit jusqu'au point virgule compris et stocke le résultat sous forme de chaîne de caractère dans le tableau de char de destination en omettant le point virgule [^;]
- Edité par rouIoude il y a 28 minutes
Pourquoi donc la méthode habituelle ne marche pas dans ce cas ? c.a.d %s;%s;%d...
on voit bien ici qu'il attrape toute la chaîne source, même l'entier puisqu'elle ne comporte pas de caractère blanc. Le point virgule n'est pas un délimiteur pour %s c'est un caractère comme un autre.
après, scanf c'est gentil, mais ça ne fait pas le job avec les vrais fichiers CSV quand un champ contient des occurrences du séparateur, du délimiteur, ou des sauts de ligne.
En plus d'être une source de débordements de tampon.
- Edité par michelbillaud 16 septembre 2021 à 18:07:49
on voit bien ici qu'il attrape toute la chaîne source, même l'entier puisqu'elle ne comporte pas de caractère blanc. Le point virgule n'est pas un délimiteur pour %s c'est un caractère comme un autre.
- Edité par rouIoude il y a 27 minutes
Ah d'accord mais du coup quel est le réel avantage de fscanf quand on a des séparateurs ? Car je pensais que vu qu'on lui donne la manière dont sont séparés les informations, elle ne prendrais pas le";"
On n'a jamais dit que scanf est la meilleure façon de faire les choses. C'est censé être la plus facile pour les débutants ... plus certain ... fgets() avec strtok() et strtoi() serait plus approprié si on connais la longueur maximum des lignes. Autrement, il faut aller en mémoire dynamique et c'est moins évident.
Le Tout est souvent plus grand que la somme de ses parties.
Du coup là je suis à la fonction de suppression des étudiants !
Je vérifie si l'étudiant est dans la bdd ( numero/email ) puis s'il y est je réécrit le fichier sans cet étudiant dans un nouveau fichier que je renomme par la suite par l'ancien ( supprimé bien évidemment )
Avec le numero , tout marche bien mais avec l'email, j'ai un petit problème !
J'ai une fonction qui me renvoie 1 si l'email de l'etudiant est dans la bdd et là elle me renvoie toujours 0 ( malgré que j'ai vérifié les informations fournies )
voici la fonction de recherche ( qui marche très bien quand je choisi l'option de rechercher un etudiant grace à son email dans le menu )
int rechercher_avec_email(FILE *infEtudiant, int taille, etudiant *Etudiant, char email[])
{
rewind(infEtudiant);
do
{
fscanf(infEtudiant,"%[^;];%[^;];%d/%d/%d;%d;%[^\n]\n", Etudiant->prenom, Etudiant->nom, &Etudiant->date_naissance.jour, &Etudiant->date_naissance.mois, &Etudiant->date_naissance.annee, &Etudiant->numero, Etudiant->email);
if (strcmp(Etudiant->email,email)==0)
{
return 1;
}
}
while (feof(infEtudiant) == 0);
return 0;
}
dans le if ayant un commentaire ( en fin de code ) il s'agit du code devant appeler une fonction qui copiera les donnés de l'ancien fichier vers le nouveau fichier ( puis suppression/renommage )
Pour le numero, ce principe marche très bien donc pas de problème de ce coté ! le seul truc qui m'empêche d'avancer c'est la fonction de recherche qui me renvoie 0
EDIT : avec des printf, les informations sont bien correctes et même dans la boucle de recherche , l'email apparait bien quand je l'affiche on dirait donc que le problème vient du strcmp !
EDIT 2 : Cependant je note que quand ma fonction supprimer_etudiant me dit ne pas avoir trouvé l'email ( ligne 25 ) ce qui retourne du printf :
Mais dans la fonction de recherche, c'est bien "test12@email.com" qui est retourné quand j'y teste un printf !
EDIT 3 : En faisant un printf du strcmp, la valeur -1 m'est retournée ( donc la première chaine est inférieure à a la seconde et dans ce cas là je ne comprend pas pourquoi )
Ou bien tu as des caractères bizarres dans un des e-mail, ou bien il y a des espaces. Fais un printf des deux e-mail en mettant un caractère devant et après: printf("e-mail = '%s'\n", email); Sinon, affiches avec une fonction du genre: #include <ctype.h> void display(char *email) { for(int i=0; email[i]; i++) { if(isprint(email[i])) printf("%c", email[i]); else printf("?"); } printf("\n"); }
Ou bien tu affiches les caractères bizarres avec le format "\\%2X"
- Edité par PierrotLeFou 17 septembre 2021 à 18:05:04
Le Tout est souvent plus grand que la somme de ses parties.
× 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.
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
Le Tout est souvent plus grand que la somme de ses parties.