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 :

Pas d'erreur sur la fonction fgets lorsqu'on dépasse le int maxLength


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre actif
    Homme Profil pro
    Ingénieur
    Inscrit en
    Avril 2020
    Messages
    88
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2020
    Messages : 88
    Par défaut Pas d'erreur sur la fonction fgets lorsqu'on dépasse le int maxLength
    Bonjour,

    Mon code source ci-dessous (extrêmement simple) :
    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
    /*
    Le But du programme ci dessous est de demandé le nom et la taille de la personne.
    On utilisera la fonction fgets() pour récupérer ses informations.
    Cette méthode est toujours à privilégier car elle est sécurisé comparé à un scanf()
    Regarder sur internet le prototype de la fonction fgets()
    Pourquoi quand on dépasse le nombre max de caractere il n'y a pas d'erreur ?
    */
     
    // BIBLIOTHEQUES :
    //===================================================
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    //===================================================
     
    // FONCTION PRINCIPALE MAIN (POINT D'ENTREE DU PROGRAMME) :
    //===================================================
    int main(void)
    {
    	// DECLARATION DES VARIABLES :
    	//===================================================
    	char prenom[10];
    	printf("Comment t'appelles tu ?\n");
     
    	// 9 caracteres et pas 10 pour reserver le caractere fin de chaine = '\0'
    	if ((fgets(prenom, 9, stdin)) != NULL)
    		printf("Tu t'appelles : %s", prenom);
     
    	else
    		printf("Erreur de saisie\n");
     
     
    	// ATTENTION fgets NE LIE QUE DES CARACTERES PAS DES NOMBRE !
    	// Ainsi le symbole 1 n'est pas vu comme le chiffre 1 mais comme le caractère 1
    	// Utiliser les fonctions de conversion string to double ou string to int ou encore string to long pour résoudre le problème
     
    	char prix[10];
    	printf("Quel est ton prix ?\n");
    	if (fgets(prix, 9, stdin) != NULL)
    		printf("Ton prix est : %g\n", strtod(prix, NULL));
     
    	else
    		printf("Erreur de saisie\n");
     
    	return 0;
    }
    //===================================================
    Lorsque je compile ce programme et que je dépasse la taille max de caractère (int maxLenght, voir le lien que je vous ai envoyé),
    il n'y a pas d'erreur qui se déclenche et mon else ne sert à rien.

    Je ne comprends pas pourquoi.
    Avez vous une explication svp ?

    Cordialement Zephyre

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    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 835
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par zephyre Voir le message
    Lorsque je compile ce programme et que je dépasse la taille max de caractère (int maxLenght, voir le lien que je vous ai envoyé),
    il n'y a pas d'erreur qui se déclenche et mon else ne sert à rien.

    Je ne comprends pas pourquoi.
    Avez vous une explication svp ?
    Ainsi, si la chaîne lue est plus longue que le buffer de réception, aucun dépassement en mémoire ne sera effectué
    Tu en demandes 9, tu en entres 150, la fonction n'en récupère quand-même que 9 (ou plutôt 8 car elle garde 1 place pour le '\0') et laisse le reste dans le buffer prêt à être récupéré au tour suivant.

    Citation Envoyé par zephyre Voir le message
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    	char prenom[10];
    	printf("Comment t'appelles tu ?\n");
     
    	// 9 caracteres et pas 10 pour reserver le caractere fin de chaine = '\0'
    	if ((fgets(prenom, 9, stdin)) != NULL)
    Justement non, la fonction se charge elle-même de la soustraction. Car là, tu n'en récupères que 8. C'est aussi écrit dans le même lien.
    Il est à noter que le nombre de caractères pouvant être lu sera au maximum de (maxLength - 1).
    Pas la peine de nous mettre des liens que visiblement tu n'as pas lus...

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    	char prenom[10 + 1];
    	printf("Comment t'appelles tu ?\n");
     
    	if ((fgets(prenom, 10 + 1, stdin)) != NULL)

    Citation Envoyé par zephyre Voir le message
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    	// ATTENTION fgets NE LIE QUE DES CARACTERES PAS DES NOMBRE !
    Que signifie cette phrase ? En quoi les caractères sont-ils liés avec fgets() ???
    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]

  3. #3
    Membre Expert Avatar de edgarjacobs
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2011
    Messages
    785
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 65
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2011
    Messages : 785
    Par défaut
    Hello,

    fgets() ne signale pas d'erreur car il n'y en a pas ! Si j'écris
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    char str[100];
    fgets(str,sizeof(str),stdin);
    fgets() lira au plus 99 caractères, et placera un '\0' en str[99]. Et ça ne génère aucune erreur si j'en entreplus de 99. Simplement, le trop plein de caractères restera dans le buffer clavier.

    Les inputs console en c ne sont pas faciles à gérer. Pour info, man fgets()

  4. #4
    Membre actif
    Homme Profil pro
    Ingénieur
    Inscrit en
    Avril 2020
    Messages
    88
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2020
    Messages : 88
    Par défaut
    Sve@r
    Pas la peine de nous mettre des liens que visiblement tu n'as pas lus...
    Je peux vous assurer que j'ai lu le lien que je vous ai envoyé.
    Cependant j'ai du mal à tout assimiler, toutes les informations.
    Veuillez m'en excuser, je n'ai pas l'habitude pourtant je sais lire ... Enfin je crois.
    Mais vous avez raison, je viens de lire plus lentement le lien que je vous ai fourni et effectivement c'est bien écrit.
    Faut vraiment que j'apprenne à lire de la doc technique sur les prototypes de fonctions.
    Et encore là j'ai de la chance car je l'ai trouvé en français.
    Merci encore pour votre précision chirurgical, c'est comme ça qu'on apprends !

    Sve@r
    Que signifie cette phrase ? En quoi les caractères sont-ils liés avec fgets() ???
    Dans le prototype de la fonction, c'est un pointeur de char.
    Ainsi tout ce qu'on récupère via une fonction fgets sera interprété comme un caractère au sens de char.
    Ça veux dire que par exemple si j'utilise la fonction fgets pour récupérer un entier par exemple 10 il faudra que je pense à le convertir avant en entier via une fonction strtoint ou un truc comme ça si je veux faire des calculs.
    C'est juste un pense bête, rien de plus.

    edgarjacobs
    Pour info, man fgets()
    Merci pour l'info y a pas mieux que le man.
    Le souci c'est que je ne suis pas trop familier pour le moment avec les termes anglais.
    Ainsi je privilégie la documentation en français.
    Je le sais pourtant car je l'ai lu mais je n'ai pas encore le bon vieux réflexe du man.
    Merci pour cette piqure de rappel !
    Et je sais également que y a pas mieux que la documentation anglaise beaucoup plus riche.

    J'ai juste une dernière question :
    Lorsque j'exécute mon programme et que je fais, alors je sais pas comment dire, vu que y a pas de dépassement mémoire autorisé par fgets(), on va dire lorsque j'entre un nombre de caractère > maxLenght -1,
    le second fgets() plante.
    Avez vous une explication ?

  5. #5
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    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 835
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par zephyre Voir le message
    Dans le prototype de la fonction, c'est un pointeur de char.
    Ainsi tout ce qu'on récupère via une fonction fgets sera interprété comme un caractère au sens de char.
    Ça veux dire que par exemple si j'utilise la fonction fgets pour récupérer un entier par exemple 10 il faudra que je pense à le convertir avant en entier via une fonction strtoint ou un truc comme ça si je veux faire des calculs.
    Déjà c'était de l'ironie sur ton orthographe et ta façon de conjuguer le verbe "lire" qui n'est pas un verbe du premier groupe et qui ne se conjugue donc pas "il lie". Ou alors on traduit ça par la conjugaison du verbe "lier" mais ce verbe n'a aucune signification vis à vis de fgets() et des caractères. Ca sert à ça l'orthographe, à exprimer sa pensée => "à essayer" et "a essayé" ne signifient pas du tout la même chose. Et donc ce n'est pas parce qu'on est en informatique que l'orthographe doit être négligée.
    Mais quelle différence fais-tu entre '1' (49) et 1 ??? Ou alors (dit dans l'autre sens) serais-tu capable d'écrire un clone de atoi() ???

    Citation Envoyé par zephyre Voir le message
    Lorsque j'exécute mon programme et que je fais, alors je sais pas comment dire, vu que y a pas de dépassement mémoire autorisé par fgets(), on va dire lorsque j'entre un nombre de caractère > maxLenght -1,
    le second fgets() plante.
    Avez vous une explication ?
    Il ne plante pas, il fonctionne parfaitement. Je te renvoie à mon précédent post et à cette partie de phrase "et laisse le reste dans le buffer prêt à être récupéré au tour suivant.". Donc au tour suivant (au second fgets) celui-ci récupère ce qui reste, ce qui est parfaitement normal. Et donc bien évidemment, puisqu'il reste encore des trucs à récupérer il n'attend pas ta saisie.
    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 chevronné
    Homme Profil pro
    très occupé
    Inscrit en
    Juillet 2014
    Messages
    137
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : très occupé

    Informations forums :
    Inscription : Juillet 2014
    Messages : 137
    Par défaut
    zephyre:

    Il y a des finesses passées sous silence dans les réponses qui t'ont été faites. Une caractéristique de fgets() est que, si fgets() a la place de le faire, il va stocker le retour à la ligne '\n' lorsque l'utilisateur presse Entrée.

    Si tu fais, comme dans ton code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    fgets(prenom, 9, stdin);
    et que tu tapes "Albert" (6 lettres), prenom va en fait contenir :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    { 'A', 'l', 'b', 'e', 'r', 't', '\n', '\0' }
    Si tu tapes "Philippe" (8 lettres), fgets termine la chaîne sans amputer les lettres composant le prénom, mais n'a pas la place de prendre le retour à la ligne (qui a aussi été tapé et que fgets() récupère s'il le peut), et prenom va alors contenir :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    { 'P', 'h', 'i', 'l', 'i', 'p', 'p', 'e', '\0' }
    et '\n' va rester dans le tampon de stdin et sera lu au prochain appel à une fonction consommant le contenu du flux stdin.

    De même, si tu tapes un mot plus grand qu'un mot de 8 lettres, '\n' ne sera pas présent dans la chaîne récupérée et sera laissé dans le tampon avec le reste des caractères non consommés.

    Du coup, si tu veux te plaindre à l'utilisateur qu'il dépasse la capacité prévue, tu peux rechercher le retour à la ligne, avec strchr() par exemple. S'il n'y est pas, c'est que la saisie a au moins laissé '\n' dans le tampon de stdin, voire plus.

    Si tu veux ignorer le reste de la saisie, tu dois purger le tampon. Une façon de faire est de faire alors ceci après fgets() :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    	int c;
    	while((c = getchar()) != '\n' && c != EOF)
    		/* discard */ ;
    Tu le ne feras après fgets() que si la chaîne récupérée ne comprend pas '\n'.

    Autre chose.

    Avec fgets(), tu as donc compris que tu récupères une chaîne comme :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    { 'A', 'l', 'b', 'e', 'r', 't', '\n', '\0' }
    du coup si tu fais
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    printf("Prénom : [%s]\n", prenom);
    alors, tu vas afficher :

    Prénom : [Albert
    ]
    Si tu ne veux pas du retour à la ligne que fgets() intègre, il te faudra le supprimer : il y a différentes façons : https://stackoverflow.com/a/2693826/8138432

  7. #7
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    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 835
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par -Eks- Voir le message
    Il y a des finesses passées sous silence dans les réponses qui t'ont été faites. Une caractéristique de fgets() est que, si fgets() a la place de le faire, il va stocker le retour à la ligne '\n' lorsque l'utilisateur presse Entrée.
    Ce n'est pas une finesse ou une caractéristique particulière, cela fait partie de son comportement général. fgets() lit le buffer demandé et stocke tout ce qui s'y trouve y compris le <return> qui, quand c'est le clavier, a été tapé pour valider la saisie et quand c'est un fichier, indique la fin d'une ligne (ces deux éléments étant représentés en C par un '\n'). Il n'y avait donc pas lieu de mentionner plus particulièrement ce point par rapport aux autres.
    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. Problème de message d'erreur sur une fonction SNMP
    Par kriptoo dans le forum Langage
    Réponses: 1
    Dernier message: 18/05/2007, 01h08
  2. Erreur sur la fonction getdate()
    Par obydissonn dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 25/04/2007, 11h48
  3. [MySQL] Erreur sur la fonction mysql_result()
    Par nico26 dans le forum PHP & Base de données
    Réponses: 5
    Dernier message: 31/01/2007, 15h50
  4. erreur sur une fonction
    Par rimbaut dans le forum C
    Réponses: 3
    Dernier message: 01/04/2006, 17h28
  5. Erreur sur une fonction avec des paramètres
    Par Elois dans le forum PostgreSQL
    Réponses: 2
    Dernier message: 05/05/2004, 21h00

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