Ok merci pour tes explication. Donc comment résoudre ce problème à part supprimer le vidage du buffer sauf pour la 2e entré.
Parce que j'ai bien essayé de trouvé mais sans succès. J'ai bien l'impression qu'il n'y a pas de solutions.
Ok merci pour tes explication. Donc comment résoudre ce problème à part supprimer le vidage du buffer sauf pour la 2e entré.
Parce que j'ai bien essayé de trouvé mais sans succès. J'ai bien l'impression qu'il n'y a pas de solutions.
Il n'y a pas de solution parce que surtout il n'y a pas de problème. Quand tu fais saisir une chaine, le '\n' fait partie de la chaine donc il est récupéré et donc ton stdin est toujours vide. Donc pas besoin de le vider.
Eventuellement il pourrait y avoir problème si tu tapes plus de caractères que ce que fgets() a prévu. Dans ce cas, elle s'arrête quand son tampon est plein et laisse le reste dans stdin. Mais dans ce cas, la saisie récupérée ne contient pas de '\n'.
Donc éventuellement si la saisie ne contient pas '\n' là tu peux vider le clavier. Exemple sur Filename_WaitingTxt qui est, dans ta version, aussi bien bancale:
Code c : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 void Filename_WaitingTxt(void) { char pInput[2]; printf("Tapé entrée pour continuer.\n"); fgets(pInput, 2, stdin); if (strchr(pInput, '\n') == NULL) Keyboard_CleanStdin(); }
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Pour compléter cette réponse, je dirais que toute la saisie effectuée au clavier est affichée à l'écran, les caractères ne restent pas bloqués quelque part, le buffer stdin est bien vidé.Eventuellement il pourrait y avoir problème si tu tapes plus de caractères que ce que fgets() a prévu. Dans ce cas, elle s'arrête quand son tampon est plein et laisse le reste dans stdin
Par contre, si la saisie dépasse la taille de la chaine passée en paramètre à fgets, ceux-ci ne seront pas stockée dans cette chaine.
Exemple :
Si tu saisie abcdef,
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 #include <stdio.h> int main() { char buffer[5]; printf("prompt : "); fgets(buffer,3,stdin); printf("valeur chaine buffer : %s",buffer); }
le résultat sera :
Tu peux voir qu'il n'y a pas de retour chariot (le prompt du shell est donc collé à la sortie du programme ), \n n'étant pas stockée dans la chaine.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 dvp@DVP:~/Documents$ ./a.out prompt : abcedf valeur chaine buffer : abdvp@DVP:~/Documents$
Tu auras un retour chariot uniquement si tu tapes juste a.
pourquoi ? car comme déjà dit le nombre de caractère possible dans la chaine sera égal à size-1 (size étant le second argument attendu par la fonction, dans l'exemple 3-1), il reste donc 2 caractères pouvant être stockés, un pour la lettre a, un pour le retour chariot. La chaine elle occupera 3 octets 'a','\n', et '\0' (le marqueur de fin de chaine représenté par un octet de valeur 0). fgets ajoute un retour chariot à la chaine si sa taille permet de le stocker. Cela peut être gênant d'avoir ce retour chariot, mais c'est le comportement de la fonction et il faut faire avec (par exemple le supprimer en ajoutant du code).
Tu remarqueras aussi que j'ai réservé 5 octets pour buffer. Par rapport à l'utilisation faite, il y a 2 caractères déclarés de trop.
Avec les fonctions chaine, tu n'a pas à te préoccuper de vider stdin. Ce n'est pas le cas avec les fonctions caractères, ou tu peux te retrouver à gérer ce problème en cas d'utilisation de séquences d'échappement.
Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
Mon article sur le P2V, mon article sur le cloud
Consultez nos FAQ : Windows, Linux, Virtualisation
Merci pour tes explications cela me permettra de mieux comprendre le fonctionnement de fgets et stdin.
Est-ce qu'il y aurai un lien pour pour avoir des précisions sur le fonctionnement de stdin et fgets ?
man fgets devrait te donner ce qu'il faut , à lire attentivement pour bien comprendre les tenants et les aboutissants. fgets sert à lire une chaine de caractères (jusqu'à un retour chariot ou la taille maxi passée à la fonction) dans un flux. On va parler de flux pour les entrées/sortie. Sous sous Unix (et donc Linux) tout est fichier. stdin correspond au descripteur de fichier correspondant au flux d'entrée, sdout correspond au flux de sortie.
Avec ces deux descripteurs de fichiers toujours présents, tu peux piloter la saisie clavier et la sortie console avec les fonctions fichiers (fopen, fclose, fread,fwrite, etc.).
Bien sûr certaines fonctions fonctionnent différemment ou n'ont pas de sens par rapport à un fichier physique. l'utilisation de fseek sur stdin n'a pas de sens et va te générer une erreur "illegal seek".
Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
Mon article sur le P2V, mon article sur le cloud
Consultez nos FAQ : Windows, Linux, Virtualisation
Ok merci pour ton aide.
J'ai retravaillé mon code et j'ai résolu mon problème en tenant compte de vos conseils.
Normalement ça marche à part pour les accents, dans l'invite de commande avec chcp 65001 c'est ok mais pour l'exécutable bin sa marche pas, il doit surement y avoir une méthode pour modifier le jeu de caractère de l'exécutable.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93 #include <stdio.h> #include <stdlib.h> #include <limits.h> // Limits chemin. #include <string.h> void Keyboard_CleanStdin(void) { int c; do { // Note : si on met stdin la console attendra toujour que l'utilisateur tape entrée, que ce soit // fgetc ou fgets pour valider. c = fgetc(stdin); }while(c != '\n' && c !=EOF); } char * Filename_RecoveryInputUser(char *pFilename) { printf("Saisir le nom du fichier.\n"); if(fgets(pFilename, PATH_MAX+1, stdin) != NULL) { char * LF = strchr(pFilename, '\n'); if(LF != NULL) *LF = '\0'; else Keyboard_CleanStdin(); } return pFilename; } FILE *Filename_OpenFile(char *pMode, char *pErrorMsg) { char pFilename[PATH_MAX+1]; // Buffer pour récupérer la saisie utilisateur. FILE *pFile = NULL; int nExit = 0; do { pFile = fopen(Filename_RecoveryInputUser(pFilename), pMode); // fopen n'admet pas les '\n'. if(pFile == NULL) { printf("Entrée un nom de fichier valide.\n"); if (pErrorMsg != NULL) printf("%s\n", pErrorMsg); nExit = 1; } else { nExit = 0; } }while(nExit); return pFile; } void Filename_WaitingTxt(void) { char pInput[2] = {}; int i = 0, nExit = 1; while(nExit) { printf("\n En attente. Tapez entrée pour continuer.\n"); if(fgets(pInput, 2, stdin) != NULL) { char *LF = strchr(pInput, '\n'); if(LF != NULL) { *LF = '\0'; nExit = 0; } else { Keyboard_CleanStdin(); } } } } int main(int argc, char const **argv) { freopen("CON", "w", stdout); FILE *pFile = Filename_OpenFile("r+", NULL); fclose(pFile); Filename_WaitingTxt(); return 0; }
C'est plus une question d'encoding de la console (je présume que tu fais ça sous console style MsDos) qui n'accepte pas les jeux de caractères étendus (elle est vieille la console MsDos !!!)
En général on laisse pisser parce que d'une part c'est du détail et d'autre part, quand vraiment on veut faire un truc de saisie solide (un truc destiné à un utilisateur lambda) on passe par des IHM style Qt (et en plus on quitte le C vraiment trop long à coder pour passer dans des langages plus riches style C# ou VB ou Python)
Tout programmé bien comme il faut, comme c'est expliqué dans les livres, avec initialisation des variables (bien qu'elles soient remplies ensuite), début de bloc, fin de bloc (même pour les blocs d'une ligne). Et donc programmé bien fade. Ca marche, je dis pas, mais c'est tellement académique que ça en devient... chiant.
Voilà. Moins de code, moins d'accolades inutiles, moins de "proutprout" et de "flonflon" mais finallement tellement plus léger !!!
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 FILE *Filename_OpenFile(char *pMode, char *pErrorMsg) { char pFilename[PATH_MAX+1]; // Buffer pour récupérer la saisie utilisateur. FILE *pFile; while (1) { pFile = fopen(Filename_RecoveryInputUser(pFilename), pMode); // fopen n'admet pas les '\n'. if (pFile != NULL) break; printf("Entrée un nom de fichier valide.\n"); if (pErrorMsg != NULL) printf("%s\n", pErrorMsg); } return pFile; }
Ma mère, qui a fait des compétitions internationales de Bridge (un jeu de carte auquel j'ai jamais rien pané) disait "un bon coup d'oeuil vaut mieux qu'une mauvaise impasse" signifiant qu'on a beau avoir tout un protocole d'annonces pour détailler son jeu à son partenaire (et aussi à ses adversaires), si on peut regarder le jeu du voisin c'est encore mieux. Là c'est un peu pareil. Peut-être que le break c'est le must du mauvais goût dans les écoles d'informatique où les professeurs sont tous bien propres, bien peignés, et savent colorier sans dépasser le bord, mais putain qu'est-ce que ça simplifie le codage !!!
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
j'ai participé (je ne suis pas étudiant) à des TDs en licence info L2 et le prof (responsable du département informatique de lyon excusé du peu et qui à travaillé aussi dans le monde professionnel) quand il a vue mon code avec des breaks, je me suis fait reprendre, parce que sa ne se fait pas, on ne sort pas proprement avec un break.
J'ai aussi il y a 2 ans, fait une formation développeur web, ont apprenaient le java, je ne m'étais pas de parenthèses dans mes codes avec les if (notamment) quand c'était possible, idem je me faisait reprendre par les formateurs et aussi les autres élèves.
De plus vs code quand je tape un while me met les accolades. Si je dois m'amuser à chaque fois à les enlever c'est relou peut-être y a t-il une option.
Ce qu'il faut comprendre, c'est que malgré le fait que je code en C depuis quelques années, je reste un débutant, un codeur du dimanche. Je n'ai aucune référence pour savoir si un code est bien ou pas j'ai des informations contradictoires qui m'arrive, entre le prof d'info (et les autres prof) qui est une référence qui te dis pas de break, les professionnels qui sont aussi des réf. qui me disent faut mettre un break etc... Moi jsuis perdu.
Ce que je veux, c'est faire du code qui soit propre et acceptable, pour que si un jour je devais montrer mes "réalisations" à un recruteur que j'ai une chance d'avoir un contrat (on rêve mais bon, l'espoir fait vivre...).
De plus je n'ai pas les moyens financier pour demander à un professionnel de corriger mes codes sources ni à un prof. d'info (qui lui me tirerait les oreilles à cause du break).
Sa fait des années que je me creuse la tête pour essayé de faire quelque chose de potable, sans savoir si sa l'ai vraiment. Alors moi qui reste un débutant je fais quoi : j'écoute les gens sur le forum, le prof qui me tombe dessus si tu ne fais pas comme il dit, la faq qui te dis faut faire comme ça, le code source du professionnel qui te met des variables globals alors qu'il faut pas, le gars qui à un niveau doctora et qui passe toutes ses variables en paramètre et sa te fait des fonctions qui font 10 mètres de long, etc.
Tien un autre prof uni qui t'écris les fonctions printf comme ça 1er fois que je vois ça :
encore une autre
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 printf("%s","\n");
Alors jluis dit quoi au prof que c'est la première fois que je vois un truc comme ça et que sur le forum dev.net je ne les aient jamais vue codé comme ça, qui à raison qui à tord qu'elle est la bonne manière de faire ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 printf("\n%s %d %s","Entrer la valeur de tab[",i,"] ");
Si tu fais comme le prof, sur le forum on peut te tombé dessus, et inversement.
Pas simple. Seul solution se faire embauché dans une boîte pour apprendre à faire de la vrai programmation.
Maintenant je peux vous passé un de mes code source, si vous avez du temps à perdre et vous me le corrigé ou a défaut par l'intermédiaire de commentaires (mis dans le code) me dire ce qui ne va pas et comment vous feriez, vous ; pour moi se serai super intéressant de voir comment en tant que professionnel vous programmer dans vos entreprises, parce que je suppose que pour la majorité, vous êtes des programmeurs professionnels avertis qui avez plusieurs années voir décennie d'expériences derrière vous.
Voilà.
Merci pour tes réponses Sve@r qui mon bien aidé et qui on été instructive pour moi et aussi pour les codes sources que tu mets sa me donne des références et merci aux autres intervenants bien sûr.
C'est normalil y a 2 "esprits". Esprit
Kernighan et Ritchie"Single Entry, Single Exit (SESE)" "1 fonction doit avoir 1 et 1 seul returnsans break pour les boucles" (le gros trait, ce que je partage) et ceux qui utilisent tout ce que le langage fourni (comme @Sve@r)
1 code propre n'existe pas1 code fonctionnel par contre lui est essentiel
Et ensuite pour la propreté du code, ce sont des concepts qui ne sont pas de la programmation :
- conception - pour minimiser les appels et l'empreinte mémoire, rendre les communications entre les objets, entre les couches le plus efficace possible, ...
- maintenance - des fonctions avec le moins de code possible, faire du code le plus générique pour minimiser les effets de bords lors des changements, ...
- métrique - empreinte mémoire mais cela peut être aussi la consommation réseau, 3D, ...
- R&D - pour avoir les algos les + performants, les + adaptés par exemple, choix des bibliothèques, ...
Merci pour ta réponse.
Il faudrait que le monde professionnel et académique accorde leurs violons sur la façon de programmer non ?
Ok. Bon déjà on ne te tombe pas dessus (quand je tombe sur quelqu'un sur le forum, il en prend pour son grade). On te donne nos versions des choses. Si ton éditeur rajoute les accolades automatiquement pas besoin de les enlever. Perso à mes débuts j'écrivais comme toi (accolade systématiques en me disant "comme ça si je dois rajouter des instructions les accolades sont déjà là") puis au fur et à mesure que je voyais que je ne rajoutais jamais des instructions j'ai compris que c'était inutile. Les histoires break/pas break ok au début on te fera chier avec mais ça ne t'empêchera pas de te forger ta propre opinion au fur et à mesure que tu coderas. Puis un jour tu seras assez à l'aise pour répondre "arrêtez de me gonfler, mes codes fonctionnent et sont lisibles et c'est ça qui compte" et de là, plus personne ne viendra te casser les noix.
Tu veux faire du code "propre", déjà pense "atomique" (une fonction ne fait qu'une chose mais le fait bien). C'est déjà ce que tu fais avec ta fonction qui fait saisir le nom du fichier et ça c'est bien. Ne perd pas cette approche. Quand tu as un truc à faire, essaye de le découper en étapes importantes et logiques puis affecte une fonction à chaque étape.
Ensuite essaye de séparer "saisie et affichage" d'un côté, "stockage" d'un autre et "calculs" sur le 3°. C'est le principe du MVC: séparer le Modèle (le stockage), la Vue (la saisie/affichage) et le Controleur (calculs). Ca te facilitera les évolutions. Tu pourras alors facilement passer d'un stockage "fichier" à un stockage "bdd" sans toucher le reste, puis d'une saisie "scanf" vers une saisie IHM sans toucher au stockage, etc.
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Laquelle d'affirmation ? Le fait que le "un seul return" soit associé à l'esprit "K&R" ou bien que certains préconisent un seul return ?
Pour le "un seul return" c'est recommandé dans certains livres d'ingéniérie de la programmation comme celui-ci qui préconisent le single-entry/single-exit. Sauf qu'ils préconisent sans vraiment dire pourquoi. Un peu dans le style "c'est mieux comme ça faites moi confiance".
Pour l'association "un seul return=K&R" ça j'en sais rien. Toutefois à l'époque de K&R, les ordis savaient moins bien gérer la mémoire qu'aujourd'hui et un seul return permettait de centraliser le point de sortie de la fonction, lequel point de sortie pouvait alors s'occuper aussi de la libération de la mémoire. Une hypothèse pourrait donc être que K&R, informaticiens professionnels, étaient donc parfaitement habitués des méthodes de programmation de l'époque et qu'ils ont fait transpirer cette habitude dans leurs écrits et leurs enseignements. Et peut-être aussi donc que c'est pour ça que cette "légende urbaine" (qui à l'origine avait probablement une raison d'exister, je ne dis pas) continue à perdurer aujourd'hui. Sauf qu'aujourd'hui, les choses ont évolué, il y a le return, le yield, l'exception, le exit et encore plein de technos diverses pour sortir et donc continuer malgré tout ça à professer le "un seul return !!!"...![]()
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Tu as été plus vite que moimais en fait cela vient plus de Edsger W. Dijkstra et encore plus généralement des langages avec 1 gestion des ressources explicite/manuelle comme le C ou l'assembleur
Le terme général est "Single Entry, Single Exit (SESE)" et voici 1 article en anglais "Single Function Exit Point" qui me semble de confiance![]()
Partager