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 :

fgets problème utilisation code de la faq


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Avril 2011
    Messages
    447
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2011
    Messages : 447
    Par défaut fgets problème utilisation code de la faq
    Bonjour,

    j'ai regardé la faq à la question : Comment lire une ligne de manière sécurisée ?

    J'ai fait un code naïf des plus simple en reprenant le code de la question de la faq mais cela me renvoi rien.
    Je suis sous mingw32-make et la version est c11.

    Voici mon code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    char * Filename_RecoveryInputUser(void)
    {
            // fgets me renvoi rien on dirait qu'il bug car il ne m'affiche même pas la chaîne.
        char *pFilename = fgets(pFilename, PATH_MAX, stdin);
        printf("%s\n", pFilename); 
        pFilename[strlen(pFilename)-1] = '\0';
        return pFilename;
    }
    De plus comme pFilename est une variable local normalement elle est détruite quand la fonction ce termine.
    Donc faire retourner pFilename même si celui-ci n'est pas null on perd l'adresse retourné non ?

  2. #2
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 766
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 766
    Par défaut
    Citation Envoyé par hbx360 Voir le message
    Donc faire retourner pFilename même si celui-ci n'est pas null on perd l'adresse retourné non ?
    Il faut recopier la chaîne de caractères avec la fonction strcpy (<- lien cplusplus.com en anglais)

    Donc soit
    • Soit tu crées 1 chaîne de caractères en local avec malloc, tu fais la recopie, et tu la retournes. Donc c'est la fonction appelante, qui récupére l'adresse retournée avec 1 assignation, et qui a la responsabilité de libérer cette chaîne de caractères.
    • Soit tu passes en paramètres 1 double pointeur char** (<- qui est en réalité l'adresse d'1 chaîne de caractères, &str), tu fais la recopie avec en déréférencent évidement.

  3. #3
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 832
    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 832
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par hbx360 Voir le message
    char *pFilename = fgets(pFilename, PATH_MAX, stdin);
    Ca c'est pas bon. fgets(s, n, flux) a pour action de récupèrer "n-1" caractères depuis "flux" et stocker ces caractères dans "s", "s" étant donc prévue pour pouvoir stocker ces "n-1" caractères (+1 pour le '\0'). Donc "s" doit être à minima un tableau de caractères soit dynamique (ie char s[1000]), soit alloué, soit provenant de l'appelant.
    Accessoirement, ensuite fgets() retourne "s" ok, mais ce retour est donc un truc déjà existant au préalable. Elle aurait pu tout aussi bien renvoyer 1 ou n ou n'importe quoi différent de 0. Là tu déclares un pointeur, pointeur qui récupère le retour d'un truc qui le reçoit en paramètre tout en n'existant pas encore. Quelque part ça ne peut pas fonctionner. C'est presque comme si tu te prenais les pieds par en dessous en espérant t'envoler.

    Pour simplifier: la partie droite du "=" est toujours évaluée avant la partie gauche. Donc tu n'as absolument pas le droit d'utiliser dans cette partie droite un élément qui n'existe pas encore.

    Citation Envoyé par hbx360 Voir le message
    Donc faire retourner pFilename même si celui-ci n'est pas null on perd l'adresse retourné non ?
    Hé oui. C'est évidemment une conséquence directe du problème ci-dessus.
    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]

  4. #4
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    En admettant que ton code soit comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <stdio.h>
    #include <string.h>
     
    #define PATH_MAX 1000
     
    char * Filename_RecoveryInputUser(void)
    {
            // fgets me renvoi rien on dirait qu'il bug car il ne m'affiche même pas la chaîne.
    	char *pFilename = fgets(pFilename, PATH_MAX, stdin);
    	printf("%s\n", pFilename); 
    	pFilename[strlen(pFilename)-1] = '\0';
    	return pFilename;
    }
    Tu devrais surtout avoir un warning de ton compilateur :
    prog.c: In function 'Filename_RecoveryInputUser':
    prog.c:10:20: warning: 'pFilename' is used uninitialized in this function [-Wuninitialized]
       9  |  char *pFilename = fgets(pFilename, PATH_MAX, stdin);
          |                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Tu as bien mis les options qui vont bien à ton compilateur ? (pour gcc et clang : -Wall -Wextra)


    Citation Envoyé par foetus Voir le message
    Il faut recopier la chaîne de caractères avec la fonction strcpy (<- lien cplusplus.com en anglais)

    Donc soit
    • Soit tu crées 1 chaîne de caractères en local avec malloc, tu fais la recopie, et tu la retournes. Donc c'est la fonction appelante, qui récupére l'adresse retournée avec 1 assignation, et qui a la responsabilité de libérer cette chaîne de caractères.
    • Soit tu passes en paramètres 1 double pointeur char** (<- qui est en réalité l'adresse d'1 chaîne de caractères, &str), tu fais la recopie avec en déréférencent évidement.
    Mais pourquoi copier avec strcpy ?

    Si on te passe le buffer, fgets() écrit dedans et c'est bon. Si non, tu crées le buffer, fgets() écrit dedans, tu le renvoies et c'est bon.

  5. #5
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 766
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 766
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Mais pourquoi copier avec strcpy ?
    Parce que je n'ai pas compris la question "Donc faire ?"

    Et donc, j'ai répondu de façon générale
    Ensuite la fonction fgets retourne son paramètre (1 truc de la libc qui permet de chaîner les appels), mais le paramètre doit être 1 vrai tableau : dans l'exemple ce n'est pas très clair
    Parce que si tu crées 1 tableau fixe local char file_str[XXX];, tu ne peux pas le retourner. Il faut faire 1 recopie

  6. #6
    Membre éclairé
    Profil pro
    Inscrit en
    Avril 2011
    Messages
    447
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2011
    Messages : 447
    Par défaut
    Le code que je vous ai posté c'est celui de la faq, il faudrait faire les modifications nécessaire je pense .

    Voici le code de la faq :

    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
     
    char * read_stdin(char * buffer, size_t taille) 
    { 
        char * result = fgets(buffer, taille, stdin); 
     
        if (result != NULL) 
        { 
            char * lf = strchr(buffer, '\n'); /* On cherche le caractère '\n'. */ 
     
            if (lf != NULL) /* S'il est présent, ... */ 
                *lf = '\0'; /* ... on le supprime    */ 
            else 
            { 
                /* 
                * Le '\n' n'est pas présent. Ça signifie qu'il reste au moins un 
                * caractère dans stdin. On peut choisir de les ignorer et de vider 
                * stdin ou d'agrandir le buffer si c'est possible (realloc()) et de 
                * rappeler fgets() autant de fois que nécessaire... 
                * 
                * Si on ne fait rien, la prochaine lecture sur stdin se fera sans attente 
                * et récupèrera ce qui n'a pas été lu ... 
                */ 
            } 
        } 
     
        return result; 
    }

    @foetus : ok compris.

    Citation Envoyé par Sve@r Voir le message

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char *pFilename = fgets(pFilename, PATH_MAX, stdin);
    Ca c'est pas bon.
    Bin c'est le code de la faq.

    @Bktero : bin je les ai pas mis je vais le faire.

    J'ai une autre question quand je veux vider le buffer en utilisant le code de la faq mais avec fgetc au lieu de getchar, j'ai le problème suivant c'est qu'il faut que je tape 2 fois entrée pour que le programme passe à la suite. Et si je dit à l'utilisateur de taper sur entrée pour continué et bien idem faut que je le fasse 2 fois. J'ai le même problème avec getchar.
    Y aurait-il une possibilité pour ne pas à avoir à taper entrée 2 fois ?


    Voici une vidéo qui montre ce problème :



    Voici mon code ou l'on entre le nom du fichier :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    char pFilename[PATH_MAX]; // Buffer pour récupérer la saisie utilisateur (stdin).
    char * Filename_RecoveryInputUser(void)
    {
    	fgets(pFilename, PATH_MAX, stdin); 
    	pFilename[strlen(pFilename)-1] = '\0';
            Keyboard_CleanStdin();
    	return pFilename;
    }
    Le code pour vider le buffer :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    void Keyboard_CleanStdin(void)
    {
      s32 c;
      do
      {
        // Note : si on met stdin la console attendra toujours que l'utilisateur tape entrée, que ce soit
    		// fgetc ou fgets pour valider.
        c = fgetc(stdin); 
      }while(c != '\n' && c !=EOF);
    }
    Mon autre code (la 2e ligne ou l'on tape entrée pour continuer) :

    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
     
    void Filename_WaitingTxt(void)
    {
    	char pInput[2] = {};
    	int i = 0;
     
    	printf("Attente. Tapez entrée pour continuer.\n");
    	fgets(pInput, 2, stdin);
    	Keyboard_CleanStdin();
     
    	while( pInput[i] != '\n')
    	{
    		printf("Tapez  entrée pour continuer.\n");
    		fgets(pInput, 2, stdin);
    		Keyboard_CleanStdin();
    	}
    }

  7. #7
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par hbx360 Voir le message
    Bin c'est le code de la faq.
    Y'a un monde entre le code de la FAQ qui prend un buffer en paramètre et l'utilise, puis stocke le retour de fgets dans une autre variable et ton truc qui crée un char* pFilename juste avant son utilisation dans fgets, sans aucune forme d'initialisation, tout en récupérant son retour dans la même variable.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Avril 2011
    Messages
    447
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2011
    Messages : 447
    Par défaut
    J'ai recopié le code de la faq.
    C'est la seul solution que j'ai trouvé, de déclarer mon tableau en variable global et de le retourner car je met la fonction dans une autre

    Voici le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    FILE *pFile = Filename_OpenFile(Filename_RecoveryInputUser(), "r", NULL);.
    ATTENTION : j'ai pas dis que je critiquais la faq je signal un problème je cherche à comprendre je ne suis pas dans une démarche violente ni agressive et je suis dans le forum débutant. Merci de ne pas être agressif !

  9. #9
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    Tu peux tourner ça dans tous les sens que tu veux, ton code et celui de la FAQ n'ont rien à voir. Et le code de la FAQ est correcte. Le tien, non.
    Quant à utiliser fgets pour retourne un char*, il t'a été expliqué plus haut comment faire.
    fgets prend un buffer. Un buffer c'est pas un pointeur random. C'est de la mémoire qui doit exister, allouée dans la heap via malloc ou sur la stack.
    Utiliser une globale pour ça c'est loin d'une bonne idée ou façon de faire.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

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

Discussions similaires

  1. Request.getParameter renvoie NULL
    Par the java lover dans le forum Servlets/JSP
    Réponses: 5
    Dernier message: 22/10/2006, 10h34
  2. [ppc] Malloc renvoie NULL !
    Par FamiDoo dans le forum C++
    Réponses: 4
    Dernier message: 18/08/2006, 10h01
  3. Operateur "new" renvoi NULL
    Par Demerzel_01 dans le forum C++
    Réponses: 25
    Dernier message: 07/07/2006, 09h43
  4. [SPL] Rewind() qui renvoie NULL
    Par fadeninev dans le forum Bibliothèques et frameworks
    Réponses: 6
    Dernier message: 06/06/2006, 15h44
  5. [JDBC]Un new qui renvoie null...
    Par Ditch dans le forum JDBC
    Réponses: 4
    Dernier message: 03/01/2005, 13h14

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