IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

La boucle ne respecte pas le premier pas


Sujet :

C

  1. #1
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2013
    Messages
    120
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Côte d'Ivoire

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2013
    Messages : 120
    Points : 109
    Points
    109
    Par défaut La boucle ne respecte pas le premier pas
    J'essaie de comprendre le fonctionement des fonctions fgets et des conversions de chaînes en nombre quelconque. Cependant je ne comprends pas
    les tours suivants de la boucle
    do... while()
    On arrive pas à saisir une deuxième note.
    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    int main(int argc, char const *argv[])
    {
    	int nbre=0;
    	int i= 1 ;
    	char val[3];
    	char c= 'O';
     
        do
    	{
    		printf("NOTE:" );
    		if(fgets(val,3, stdin) !=NULL);
    		 nbre= atoi(val);
     
    		if (nbre>=0 && nbre<=20)
    		{
     
    			printf("MOYENNE: %.2f \n", (float)(nbre/i) ) ;
    		    i++ ;
     
    		}
     
    		printf("Voulez vous continuer? O/N:");
     
    		c=getc(stdin) ;
     
    	}while(c == 'O') ;
     
     
    	return 0;
    }

  2. #2
    Membre expérimenté

    Homme Profil pro
    Responsable des études
    Inscrit en
    Mars 2009
    Messages
    553
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Responsable des études
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2009
    Messages : 553
    Points : 1 672
    Points
    1 672
    Par défaut
    Copie d'écran ?

  3. #3
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Bonjour,

    - La console attend la saisie de caractères qu'elle mémorise. Dès qu'elle reçoit un retour chariot, l'ensemble des caractères et la fin de ligne sont transmis dans un buffer.
    - La fonction fgets lit dans ce buffer (elle attend tant qu'il n'y a pas assez de caractères ou qu'avant la fin, une fin de ligne ou une fin de fichier est reçue.) Ici le nombre de caractères vaut 2.
    - La fonction getc lit un caractère dans le buffer (elle attend au moins un caractère ou une fin de ligne ou une fin de fichier.)

    Alors, que se passe-t-il ?
    - fgets() attend;
    - l'utilisateur tape "10\n", le buffer contient "10\n";
    - fgets() extrait "10" qui donne le nombre 10;
    - getc() lit le caractère restant dans le buffer '\n';
    - ça n'est pas 'O', c'est fini.

    Autre scénario:
    - fgets() attend;
    - l'utilisateur tape "2\n", le buffer contient "2\n";
    - fgets() extrait "2\n", qui donne le nombre 2;
    - getc() attend;
    - l'utilisateur tape "O\n";
    - getc() lit le 'O', il reste "\n" dans le buffer;
    - on peut continuer;
    - fgets() lit dans le buffer le "\n" qui restait, qui donne un nombre non valide;
    - getc() attend;
    - ...

    Alors attention quand on utilise des fonctions fgets() et getc() successivement, la solution n'est pas simple...

  4. #4
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 370
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 370
    Points : 23 625
    Points
    23 625
    Par défaut
    Et bien sûr, attention à bien taper « O » et pas « o »…

  5. #5
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Bonjour

    Tu as soulevé un des points les plus difficiles à maitriser: la gestion de ton clavier.

    Déjà tu as dû remarquer que ton souci n'apparaissait qu'avec des notes à 2 chiffres (10, 11, 12, ..., 20). En effet, quand tu saisis "12", tu appuies sur '1', puis '2' puis '<entree>'. Ton clavier stockant tout ce que tu as appuyé, il contient alors ces 3 éléments.
    Ensuite tu demandes à fgets() de récupérer le contenu de ton clavier en lui indiquant que la zone réceptrice fait 3 octets. fgets() va donc en récuperer 2 (elle réserve une place pour y stocker le '\0'). Elle stocke donc dans "val" les éléments '1', '2' et '\0'. Le '\n' reste donc dans le clavier.
    Ensuite, au getc() suivant, le clavier n'étant pas vide, la fonction n'a pas besoin de s'arrêter pour te laisser taper un truc et récupère ce '\n' qui va être stocké dans "c". La variable "c" ne contenant pas 'O', la boucle ne recommence pas.

    Solution: éliminer ce '\n' avant le getc(). Tu pourrais penser à rajouter un "getc()" supplémentaire sous le "fgets()" sauf que ce souci n'apparait pas avec les notes à 1 chiffre. A ce moment là, le clavier étant déjà vide, ton programme bloquerait connement à attendre un truc au clavier.
    Donc la solution est de laisser fgets() gérer une saisie de 3 touches possibles en remplaçant "3" par "4" (rappel à toujours savoir: quel que soit le nombre que tu mets, fgets() retire "1" pour y stocker le '\0'). Comme la fonction s'arrête aussi au <return>, elle pourra gérer les notes à 1 chiffre tout comme les notes à 2 chiffres. Toutefois elle partira dans le décors si l'utilisateur tape "toto" (souci de contrôle de la chose saisie).
    Autre solution pour gérer ce second cas: tu montes la zone de saisie à (par exemple) 1024 octets et utilises ensuite sscanf() pour récupérer tout nombre se trouvant dans la zone saisie. Dans ce cas là, comme la fonction sscanf() retourne le nombre d'items récupérés, tu peux même savoir si la saisie est valide ou pas.

    PS: tu auras un soucis analogie à la saisie "O/N". Si tu réponds "O", tu saisiras 'O' + '\n'. Le getc() récupèrera ce 'O' mais laissera le '\n' dans le clavier qui ira pourrir le fgets() de l'itération suivante. Et si tu rajoutes un "getc()" supplémentaire tu auras des soucis si l'utilisateur ne répond rien à la question O/N. Donc là aussi vaut mieux passer par fgets() et une zone tampon intermédiaire.

    PS2: tu devrais réfléchir au résultat de la division de "nbre/i", ces deux éléments étant des entiers...

    PS3: réfléchis aussi à l'action du point-virgule au bout de ton if...

    PS4: pourquoi 1024 ? Il s'agit d'un nombre consensuel indiquant "buffer". Quand tu veux créer un buffer d'une taille suffisante pour gérer des cas standards, tu peux utiliser la valeur que tu veux (100, 200, 500). Mais utiliser un nombre quelconque induira tout autre utilisateur à se poser des questions (pourquoi 100? pourquoi 200? pourquoi 500?). Alors qu'utiliser une puissance de 2 (256, 512, 1024, 2048) est une indication conventionnelle. Les autres lecteurs/codeurs (tu ne sais jamais ce que peut devenir ton programme et qui peut être amené à le faire évoluer) comprendront immédiatement que tu as mis "1024" parce que justement tu n'en avais rien à cirer de la taille exacte. Donc en effet, on met une taille ayant une signification particulière pour indiquer que cette taille n'en a en réalité aucune.
    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]

  6. #6
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2013
    Messages
    120
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Côte d'Ivoire

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2013
    Messages : 120
    Points : 109
    Points
    109
    Par défaut
    Vraiment merci pour l’éclairage sur la fonction fgets et fgetc.

    Citation Envoyé par Sve@r
    Autre solution pour gérer ce second cas: tu montes la zone de saisie à (par exemple) 1024 octets et utilises ensuite sscanf() pour récupérer tout nombre se trouvant dans la zone saisie. Dans ce cas là, comme la fonction sscanf() retourne le nombre d'items récupérés, tu peux même savoir si la saisie est valide ou pas.
    j'avoue que je ne sais comment utiliser la fonction sscanf.
    comme ca?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    	char t[1024]= "Salut";
    	sscanf(t, "%s") ;
    	printf("%s\n",t );
    Mais ne marche pas.
    donnez moi un exemple de comment l'utiliser.

  7. #7
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    exactement comme scanf, mais avec un premier argument supplémentaire, la chaine à lire à la place de stdin.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  8. #8
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par free_01_binairy Voir le message
    j'avoue que je ne sais comment utiliser la fonction sscanf.
    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
    #include <stdio.h>
    int saisie_int(char *prompt, char *err) {
    	char t[1024 + 1];
    	int val;
    	while (1) {
    		fputs(prompt, stdout);
    		fgets(t, 1024 + 1, stdin);
     
    		// Je vais demander à sscanf de stocker un entier ("%d") dans "val" en prenant les datas dans "t" et non au clavier. Elle renverra le nb d'entiers correctement récupérés. Suffit donc de regarder si ce nb vaut 1 puisque je veux "un" entier...
    		if (sscanf(t, "%d", &val) == 1) break;
     
    		// Ici je sais que je n'ai pas réussi à récupérer mon entier => forcément il y a un blem dans la saisie...
    		fprintf(stderr, "%s - Recommencez\n", err);
    	}
    	return val;
    }
     
    int main() {
    	int x=saisie_int("Entrez un nombre entier :", "Cette saisie n'est pas un nombre entier");
    	printf("%d\n", x);
    }
    PS: pourquoi "+1" ? Pour indiquer aux autres que tu as bien pensé à garder une place pour le '\0' qui est systématiquement inséré à chaque chaine créée/remplie...
    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]

  9. #9
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2013
    Messages
    120
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Côte d'Ivoire

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2013
    Messages : 120
    Points : 109
    Points
    109
    Par défaut
    Je crois ceci est correct après avoir suivi vos conseils.

    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
    int main(int argc, char const *argv[])
    {
     
    	float note=0;
    	float somme=0 ;
    	int i= 1 ;
    	char val[1024];
    	char R[1024];
     
    	do
    	{
    		printf("NOTE:" );
     
    		if( ( fgets(val,1024, stdin) !=NULL ) )
    		{
    			if ( sscanf(val, "%f", &note) ==1 )
    			{
    				if (note>=0 && note<=20)
    				{
                        somme= somme + note;
    					printf("MOYENNE: %.2f \n", somme/i ) ;
    					i++ ;
     
    				}
    			}
    		}
     
    		printf("Voulez vous continuer? O/N:");
    		fgets(R, 1024, stdin);
    		if (strlen(R)>1) // s'il ne saisis pas un seul caractere, on supposera sa reponse à NON
    		{
    			R[0]= 'N' ;
    		}
     
    	}while(R[0] == 'O') ;
     
     
    	return 0;
    }
    J'attends vos suggestions pour les modifications à apporter.
    Cependant j'ai pas fini avec les difficultés qu'on a pour la saisie securisée des données.

  10. #10
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2013
    Messages
    120
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Côte d'Ivoire

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2013
    Messages : 120
    Points : 109
    Points
    109
    Par défaut
    Citation Envoyé par dalfab
    La fonction fgets lit dans ce buffer
    Mais le buuffer c'est quoi au juste? jusque la je croyais que le buffer c'est le tableau qe je crée pour contenir mes données saisies au clavier.
    A vous entendre parler, il ne s'agirait pas de ça. Puisque mon buffer (enfin selon ma defintion à moi) doit contenir 3 caractères. donc si on saisis un caractère de plus cela devait être absent de mon buffer puisqu'il ne peut en contenir autant. ou est donc stoké le caractère '\n' puisqu'il est absent de mon tableau "val" pour revenir encore pourir mon buffer perso?

    Citation Envoyé par Sve@r
    Déjà tu as dû remarquer que ton souci n'apparaissait qu'avec des notes à 2 chiffres (10, 11, 12, ..., 20). En effet, quand tu saisis "12", tu appuies sur '1', puis '2' puis '<entree>'. Ton clavier stockant tout ce que tu as appuyé, il contient alors ces 3 éléments.
    Ensuite tu demandes à fgets() de récupérer le contenu de ton clavier en lui indiquant que la zone réceptrice fait 3 octets. fgets() va donc en récuperer 2 (elle réserve une place pour y stocker le '\0'). Elle stocke donc dans "val" les éléments '1', '2' et '\0'. Le '\n' reste donc dans le clavier.
    Ensuite, au getc() suivant, le clavier n'étant pas vide, la fonction n'a pas besoin de s'arrêter pour te laisser taper un truc et récupère ce '\n' qui va être stocké dans "c". La variable "c" ne contenant pas 'O', la boucle ne recommence pas.
    Quand mon clavier stocke les donées les touches au clavier, ou les stocke-t-il? n'est pas dans mon tableau "val" ? et le reste qu'il ne peut en contenir, ou le rejette-t-il? cette préoccupation rejoint celle que j'ai soumise `@dalfba`

    La fonction scanf a un comportement similaire, me parait-il, celui de ne pas vider le buffer et de laisser des déchets en son sein.
    Alors ma grande question, commnet faire pour vider le buffer ( selon la definition correcte qu'on peut lui donner.) pour qu'une saisie suivante puisse etre correcte.

    VOICI UN TEXTE QUE J'AI LU QUELQUES PART DANS MES RECHERCHES.

    Bufferisation
    La sortie standard est bufferisée: Les fonctions d’Entrées/Sortie de
    <stdio.h> n’envoient pas directement les éléments sur l’écran.
    UNIX incite à l’enchaı̂nement de commandes ou exécutables via des
    pipes. Mais la communication entre les processus a un coût. Surtout
    si l’on perd son temps à communiquer sans arrêt des messages tout
    petits.
    printf écrit sur le buffer de la sortie standard (de taille 8192 Octets
    par défaut) et une fois le buffer plein (ou un retour à ligne, ou un
    flush, ou ...), on sollicite le processus d’affichage à l’écran.
    Note: La sortie d’erreur n’est pas bufferisé et affiche les caractères
    dès l’ajout dans le flux.
    ils ont ajouté cet exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    int main(void)
    char* nom="Jean";
    	printf("Ou est l'erreur de segmentation?");
    	 nom[30]= 123;
    return 0 ;
    programme correct:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    int main(void)
    char* nom="Jean";
          //Un saut de ligne force la vidange du buffer
    	printf("Ou est l'erreur de segmentation\n?");
    	 nom[30]= 123;
    return 0 ;
    La chose meme impliquerait meme la fonction printf
    Je veux un peu d'explication sur cette partie: printf("Ou est l'erreur de segmentation\n?");et printf("Ou est l'erreur de segmentation?");

  11. #11
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Les deux buffers d'entrée et de sortie sont des mécanismes internes du système et de la bibliothèque système.

    Ce sont des tableaux cachés auxquels tu n'as pas accès. A priori, ils sont quelque part dans la structure FILE pointé par stdin et stdout.

    Chaque fonction qui utilise stdin ou stdout passe par ces buffers, en vérifiant leur taux de remplissage.

    Bien qu'elle soit écrite pour le C++, l'explication donnée à la question Qu'est-ce qu'un tampon, un buffer ? est valable pour le C.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  12. #12
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2013
    Messages
    120
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Côte d'Ivoire

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2013
    Messages : 120
    Points : 109
    Points
    109
    Par défaut
    Bien qu'elle soit écrite pour le C++, l'explication donnée à la question Qu'est-ce qu'un tampon, un buffer ? est valable pour le C.
    Le lien que vous m'avez fourni me rappelle une chose, celle de la vidange du buffer:
    A quel moment doit-on utiliser la fonction fflush pour vider le buffer?
    J'ai lu certaines choses dans la doc, mais la langue de shakespeare n'est pas mon fort donc la compréhension n'a été trop ça.
    12.20.2 Flushing Buffers
    Flushing output on a buffered stream means transmitting all accumulated characters to the
    file. There are many circumstances when buffered output on a stream is flushed automati-
    cally:
    • When you try to do output and the output buffer is full.
    • When the stream is closed. See Section 12.4 [Closing Streams], page 259.
    • When the program terminates by calling exit. See Section 25.7.1 [Normal Termina-
    tion], page 759.
    • When a newline is written, if the stream is line buffered.
    • Whenever an input operation on any stream actually reads data from its file.
    If you want to flush the buffered output at another time, call fflush, which is declared
    in the header file stdio.h.
    int fflush ( FILE *stream )
    [Function]
    Preliminary: | MT-Safe | AS-Unsafe corrupt | AC-Unsafe lock corrupt | See
    Section 1.2.2.1 [POSIX Safety Concepts], page 2.
    This function causes any buffered output on stream to be delivered to the file. If
    stream is a null pointer, then fflush causes buffered output on all open output
    streams to be flushed.
    This function returns EOF if a write error occurs, or zero otherwise.
    Excusez moi je vous demande pas de me le traduire mais juste les grandes lignes essentielles.

  13. #13
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 370
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 370
    Points : 23 625
    Points
    23 625
    Par défaut
    C'est effectivement un thème qui a été maintes fois débattu ici tant il est sujet à confusions sournoises.

    « to flush » signifie en gros « tirer la chasse » et cela sert à vider un buffer en provoquant l'envoi immédiat de ce qu'il contient vers sa destination finale, avant cet envoi ne se fasse naturellement. Par exemple, tout ce qui est écrit vers la sortie standard est automatiquement envoyé vers le terminal quand une ligne est complète, donc qu'on a écrit un retour à la ligne. Si tu as besoin que l'affichage soit « à jour », par exemple si tu gères une barre de progression ou si tu as l'intention de modifier cet affichage à l'étape d'après, tu écris fflush(stdout) et tout ce qui est en attente dans le buffer sera traité.

    Il est important de noter que tu ne peux pas utiliser une astuce du style fflush(stdin) pour vider le buffer d'entrée (par exemple pour lire le clavier de façon saine) et ce pour la bonne raison que, là encore, fflush() ne sert pas à abandonner le contenu d'un buffer mais à provoquer son envoi immédiat vers son destinataire.

  14. #14
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par free_01_binairy Voir le message
    Mais le buuffer c'est quoi au juste? jusque la je croyais que le buffer c'est le tableau qe je crée pour contenir mes données saisies au clavier.
    C'est un nom générique signifiant "zone tampon". C'est pas parce que tu crées tes propres buffers qu'il n'y en a pas d'autres déjà existants.

    Citation Envoyé par free_01_binairy Voir le message
    A vous entendre parler, il ne s'agirait pas de ça. Puisque mon buffer (enfin selon ma defintion à moi) doit contenir 3 caractères. donc si on saisis un caractère de plus cela devait être absent de mon buffer puisqu'il ne peut en contenir autant. ou est donc stoké le caractère '\n' puisqu'il est absent de mon tableau "val" pour revenir encore pourir mon buffer perso?
    Quand mon clavier stocke les donées les touches au clavier, ou les stocke-t-il? n'est pas dans mon tableau "val" ?
    Ton programme, au lancement, hérite de 3 buffers déjà tout faits: stdin (tout ce qui entre, généralement le clavier), stdout (pour faire sortir toute information qualifiée de "normale", généralement l'écran) et stderr (pour faire sortir toute information qualifiée d'anormale parce que traduisant un souci, généralement là aussi l'écran).
    Quand tu demandes fgets(val, 3, stdin) tu demandes à la fonction de récupérer 2 caractères de "stdin" et les transférer dans "val". Alors pourquoi passer de "stdin" à "val" ? Parce que c'est plus facile de manipuler un tableau local (tu peux lire le premier octet, le second, le remplacer, etc, choses que tu ne peux pas faire avec "stdin"). Mais si "stdin" contient 12 caractères, ben comme fgets() n'en récupère que 2, les 10 autres restent dedans.

    Citation Envoyé par free_01_binairy Voir le message
    et le reste qu'il ne peut en contenir, ou le rejette-t-il?
    "stdin" ne rejette rien. s'il est plein alors il bloquera tout ce qui est suceptible d'y mettre des trucs dedans (donc par défaut ton clavier) jusqu'à ce que ton programme ait traité son contenu et libéré de la place.

    Citation Envoyé par free_01_binairy Voir le message
    La fonction scanf a un comportement similaire, me parait-il, celui de ne pas vider le buffer et de laisser des déchets en son sein.
    scanf() est une des nombreuses fonctions permettant de récupérer des trucs depuis "stdin". Toutes ces fonctions ont au minimum ce point commun que tout ce qui est récupéré de "stdin" disparait de "stdin". Donc jamais de déchet.

    Citation Envoyé par free_01_binairy Voir le message
    Alors ma grande question, commnet faire pour vider le buffer ( selon la definition correcte qu'on peut lui donner.) pour qu'une saisie suivante puisse etre correcte.
    En théorie tu ne devrais jamais avoir besoin de vider stdin. A tel point qu'il n'existe aucun outil dédié à ce travail. Si tu sais gérer stdin, détecter les saisies incorrectes, etc, alors stdin est toujours clean. Une des raisons est déjà que stdin n'est pas forcément rattaché au clavier. Si tu bosses dans le monde Unix/Linux tu as à ta disposition des mécanismes de communication entre les programmes (les pipes) qui te permettent de demander au programme A de rediriger tout son stdout vers le stdin du programme B (et éventuellement continuer depuis stdoutB vers stdinC et etc etc etc). Ca permet une indépendance totale des programmes qui n'ont besoin que de lire "stdin", faire le traitement pour lesquels ils sont programmés et renvoyer le résultat vers "stdout" sans se préoccuper ensuite de ce résultat (sera-t-il imprimé ? mailé ?? archivé ??? il s'en balance).
    Charge ensuite à l'utilisateur de les assembler judicieusement (comme des légos) pour faire un truc complexe. Par exemple ceci ls | wc. Le programme "ls" a pour but de lister tes dossiers et afficher cette liste dans stdout (par défaut l'écran). D'un autre coté, le programme "wc" a pour but de compter les lignes, mots et caractères d'un fichier ou de stdin (donc le clavier) s'il n'y a pas de fichier. Mais en insérant un pipe ("|") entre les deux commandes, cela les relie via leur stdin/stdout ce qui a pour résultat de rediriger toute la liste donnée par "ls" non plus dans stdout mais dans le stdin du compteur "wc". Au final on obtient le nombre de lignes affichées par "ls" donc le nombre de fichiers. Et si je ne veux plus les compter mais les mailer vers mon pote situé ailleurs, alors je remplace ls | wc par ls | mail "mon pote@ailleurs". Et si je veux les convertir en majuscules entre temps, alors je rajoute ls | tr '[:lower:]' '[:upper:]' |mail "mon pote@ailleurs". Et si je veux les lui envoyer dans l'ordre alphabétique inverse (de "z" vers "a"), alors ls | tr '[:lower:]' '[:upper:]' |sort -r |mail "mon pote@ailleurs".
    Mais ce système ne peut fonctionner que si les programmeurs qui codent ces différents programmes ("wc", "mail", "tr", "sort") savent manipuler stdin et ne se mettent pas dans l'idée de le purger au préalable...

    Toutefois si jamais cela devait arriver quand-même (on ne sait jamais) alors un truc basé sur while (fget(stdin) != EOF) te vide stdin.

    Citation Envoyé par free_01_binairy Voir le message
    Je veux un peu d'explication sur cette partie: printf("Ou est l'erreur de segmentation\n?");et printf("Ou est l'erreur de segmentation?");
    On en revient au buffer qui sert de "tampon". Et un tampon n'est pas présumé devoir délivrer ses informations immédiatement. Il en est donc de même pour le buffer "stdout" dans lequel printf() vient écrire des trucs. Ce truc est alors stocké dans "stdout" et ne sera délivré à l'écran que dans 3 cas
    1. quand stdout est plein
    2. quand stdout reçoit un ordre de vidage que lui envoie la fonction fflush() ou que lui envoie le programme qui se termine proprement
    3. quand stdout détecte un "\n" dans les caractères à afficher

    D'où ce second code qualifié de "correct" parce que le message se termine par "\n" donc on est certain qu'il s'affichera à l'écran avant que l'instruction nom[30]=123 ne s'exécute (cette instruction provoquera un crash parce qu'il est interdit d'écrire dans une chaine statique comme cela est défini plus haut).
    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]

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 19/11/2015, 11h25
  2. Saisie ne prenant pas le premier élément de la boucle
    Par sk8trasher dans le forum Débuter
    Réponses: 12
    Dernier message: 26/06/2012, 21h32
  3. [Doctrine] Pas d'index, pas de timestamp, pas de valeur par defaut
    Par Snooky68 dans le forum ORM
    Réponses: 1
    Dernier message: 30/06/2011, 10h22
  4. Réponses: 1
    Dernier message: 07/04/2006, 13h35
  5. Réponses: 2
    Dernier message: 14/04/2004, 19h37

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo