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 :

fonction utilisant fgets fonctionnant dans un projet mais pas dans un autre


Sujet :

C

  1. #1
    Membre à l'essai
    Homme Profil pro
    Webmaster
    Inscrit en
    Janvier 2013
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Webmaster
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Janvier 2013
    Messages : 13
    Points : 16
    Points
    16
    Par défaut fonction utilisant fgets fonctionnant dans un projet mais pas dans un autre
    Bonjour, je debute en langage C, surtout dans la gestion des chaines de caractères.
    J’ai voulus créer une fonction demandant une saisie utilisateur comme à l’instar de la fonction ‘request’ (langage basic de la TI92).
    J’ai concu un projet testant diverses fonctions que dispose la pluapart de langage basic :
    void mids(char chaine[], int pos, int nb);
    int instring(char chaine[], char substr[]);
    void left(char chaine[], int nb);
    void right(char chaine[], int nb);
    char *substr(char *chaine, int p, int length);
    char *str();
    char *rturnC(void);
    char *rturnC2(char * chaine);
    char *request(char *txt);
    Mon soucis est le suivant : la fonction request ne fonctionne pas, elle ne demande aucune saisie.
    Hors, j’ai créé un projet simplifié :
    Listing main.c
    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
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "str.c"
     
    int main(int argc, char *argv[])
    {
        char *r, cst[] = "FIN";
        int cnt = 1;
        r = request("Please enter your name ");
        printf("Hello %s, how are you ?\n\n", r);
        while (cnt)
        {
            printf("Continu press any key while 'FIN'\n");
            r = request("Please press anykey and 'RETURN' ");
            if (strcmp(r, "FIN") == 0)
                cnt = 0;
            printf("String in mem : >%s<\n\n", r);
        }
        printf("Fin du programme !!\n");
        return 0;
    }
    Listing str.C
    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
     
    #include "str.h"
    #define TAILLE_BUFFER 1000
    #define TAILLE_MAX (TAILLE_BUFFER - 1)
     
    char *request(char *txt)
    {
        int i, dimStr;
        char *tmp;
        printf("%s : ", txt);
        char buffer[TAILLE_BUFFER];
        fgets(buffer, TAILLE_MAX, stdin); //warn buffer = "test" >> "t.e.s.t.\n.\0"
        dimStr = strlen(buffer); // dimStr = 5
        buffer[dimStr - 1] = '\0'; //remplace '\n' by '\0'
        tmp = malloc(strlen(buffer) + 1); //add 1 pour '\0'
        if (tmp == NULL)
        {
            fputs(stderr, "Error Allocation : Nok !!");
            exit(EXIT_FAILURE);
        }
        for (i = 0; i < dimStr; i++)
        {
            tmp[i] = buffer[i];
        }
        return tmp;
    }
    LListing str.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    #ifndef STRING_H_INCLUDED
    #define STRING_H_INCLUDED
    char *request(char *txt);
    #endif // STRING_H_INCLUDED
    Ce projet lui, s’execute correctement :
    On entre ‘scroller’ puis ‘essai’, ‘encore’, ‘iygzeriprez’
    et ‘FIN’
    On obtient l’ecran suivant :
    Please enter your name : scroller
    Hello scroller, how are you ?

    Continu press any key while ‘FIN’
    Please press anykey and ‘RETURN’ : essai
    String in mem : >essai<

    Continu press any key while ‘FIN’
    Please press anykey and ‘RETURN’ : encore
    String in mem : >encore<

    Continu press any key while ‘FIN’
    Please press anykey and ‘RETURN’ : iygzeriprez
    String in mem : >iygzeriprez<

    Continu press any key while ‘FIN’
    Please press anykey and ‘RETURN’ : FIN
    String in mem : >FIN<

    Fin du programme !!

    Process returned 0 (0x0) execution time : 33.125 s
    Press any key to continue.
    _
    J’aimerais savoir pourquoi cette fonction fonctionne dans ce projet mais pas dans le premier ????

  2. #2
    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 scroller Voir le message
    J’aimerais savoir pourquoi cette fonction fonctionne dans ce projet mais pas dans le premier ????
    Bonjour

    Faudrait connaitre le premier projet... Surtout que si une fonction s'exécute bien dans un cas et pas bien dans l'autre, alors cela ne vient pas de la fonction (sauf si la fonction a un code qui produit un comportement indéterminé mais ce n'est pas le cas ici).

    Eventuellement si dans le premier projet tu as du scanf("%d") alors ça pourrait être un début de piste. En effet, le scanf n'est pas fait pour une saisie humaine et surtout avec du "%d" car dans ce cas, tout caractère qui n'est pas numérique reste alors dans stdin, y compris le <return> sur lequel tu appuies pour valider ta saisie. Et ensuite le fgets() de ton request() récupère alors ce <return> au lieu de la saisie attendue.
    Si c'est le cas, rajoute (palliatif) un fgetc(stdin) en dessous de tous tes scanf("%d"). Ensuite fouille un peu la FAQ de ce forum sur comment faire des saisies sécurisées.

    Concernant ton request, c'est dommage de recopier ta saisie élément par élément alors qu'il y a strcpy() qui le fait très bien. Et sinon on ne termine jamais une sous-fonction par exit. Le exit est réservé au main. Si une sous-fonction n'arrive pas à faire son travail, alors elle remonte le problème à l'appelant qui prend une décision (autre qu'exit évidemment) et ainsi de suite jusqu'au main.

    Code c : 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
    char *request(char *prompt)
    {
        char *tmp;
        char buffer[TAILLE_BUFFER + 1];  //add 1 pour '\0'
     
        printf("%s : ", prompt);
        fflush(stdout);
     
        fgets(buffer, TAILLE_BUFFER + 1, stdin); //+1 parce que fgets() enlève de son coté 1 pour le '\0'
        if ((tmp=strchr(buffer, '\n')) != NULL) *tmp='\0'; //remplace '\n' s'il s'y trouve par '\0' sinon ne fait rien
     
        tmp = malloc((strlen(buffer) + 1) * sizeof char); //add 1 pour '\0'
        if (tmp == NULL)
        {
            fputs(stderr, "Error Allocation : Nok !!");
            return NULL;
        }
        strcpy(tmp, buffer);
        return tmp;
    }
    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 à l'essai
    Homme Profil pro
    Webmaster
    Inscrit en
    Janvier 2013
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Webmaster
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Janvier 2013
    Messages : 13
    Points : 16
    Points
    16
    Par défaut
    Merci Sve@r, pour ta reponse et ta correction de la fonction !!

    Eventuellement si dans le premier projet tu as du scanf("%d") alors ça pourrait être un début de piste. En effet, le scanf n'est pas fait pour une saisie humaine et surtout avec du "%d" car dans ce cas, tout caractère qui n'est pas numérique reste alors dans stdin, y compris le <return> sur lequel tu appuies pour valider ta saisie. Et ensuite le fgets() de ton request() récupère alors ce <return> au lieu de la saisie attendue.
    Si c'est le cas, rajoute (palliatif) un fgetc(stdin) en dessous de tous tes scanf("%d"). Ensuite fouille un peu la FAQ de ce forum sur comment faire des saisies sécurisées.
    Effectivement c'est bien un scanf("%d") qui posait probleme,
    dans mon premier projet j'ai une fonction menu auquel on envoi un string affichant les rubriques et un entier contenant le maximum que l'utilisateur peut choisir.
    l'utilisateur selectionne bien le menu desire via un scanf("%d").
    Lors de l'appel de ma fonction 'request' le fgets semblait inactif mais maintenant ca s'explique si il recupère la touche <Entrée> précédement enregistré.

    Probleme resolu avec 'fgetc(stdin);'
    par contre j'ai pas eu besoin d'utiliser 'fflush(stdout);'
    ce doit être un autre moyen pour vider la memoire d'entree / sortie clavier egalement non ?

    c'est dommage de recopier ta saisie élément par élément alors qu'il y a strcpy() qui le fait très bien
    Exact, c'est que je ne voulais pas (a tord vu qu'elle est bien defini par une allocation dynamique) que la variable retourné soit de la taille de la variable 'buffer' de taille géante !!

    Merci pour cette réponse rapide, désolé pour mon retard, voilà seulement que je suis en train de tester le nouveau code !!

  4. #4
    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 scroller Voir le message
    Effectivement c'est bien un scanf("%d") qui posait probleme,
    Probleme resolu avec 'fgetc(stdin);'
    Oui, un fgetc juste en dessous du scanf("%d") c'est bien. Mais ça ne te protège pas contre une saisie incorrecte (si l'utilisateur entre "toto" par exemple).
    Autre méthode à base de sscanf
    Code c : 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
    int get_int(char *prompt, int *c)
    {
        char buf[1024];
        fputs(prompt, stdout);
        fflush(stdout);
        fgets(buf, 1024, stdin);
        return sscanf(buf, "%d", c);
    }
     
    int main()
    {
        int n;
        if (get_int("Entrez votre nombre: ", &n) == 0)
           printf("Saisie incorrecte !!!\n");
        else
            printf("Vous avez saisi %d\n", n);
    }

    Avec cette façon de faire, déjà sscanf te renvoie le nombre d'éléments correctement récupérés donc tu peux savoir si la saisie est correcte ou pas et toute saisie quelle qu'elle soit t'assure un stdin toujours clean. Ensuite tu peux éventuellement renforcer la fonction
    Code c : 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
    int get_int(char *prompt)
    {
        char buf[1024];
        int n;
        while (1)
        {
            fputs(prompt, stdout);
            fflush(stdout);
            fgets(buf, 1024, stdin);
            if (sscanf(buf, "%d", &n) > 0) break;
            fputs("Saisie incorrecte - Recommencez !!!\n", stdout);
        }
        return n;
    }
     
    int main()
    {
        int n;
        n=get_int("Entrez votre nombre: ");
        printf("Vous avez saisi %d\n", n);
    }

    Citation Envoyé par scroller Voir le message
    par contre j'ai pas eu besoin d'utiliser 'fflush(stdout);'
    ce doit être un autre moyen pour vider la memoire d'entree / sortie clavier egalement non ?
    C'est pour être sûr que la chaine s'affiche à ce moment là (stdout est bufferisé et une chaine qui ne contient pas de "\n" ne s'affiche pas forcément au moment où on le demande)...
    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: 3
    Dernier message: 11/05/2014, 22h24
  2. [Débutant] Méthode d'une classe fonctionne dans un projet mais pas ailleurs
    Par kryptong dans le forum C#
    Réponses: 1
    Dernier message: 27/02/2013, 20h52
  3. Requete SQL BETWEEN fonctionne dans le bash mais pas dans mon script?
    Par ssc37 dans le forum Shell et commandes GNU
    Réponses: 2
    Dernier message: 09/03/2009, 11h01
  4. Réponses: 9
    Dernier message: 13/03/2008, 01h34
  5. [RegEx] Regex qui fonctionne dans un preg_replace mais pas dans un ereg
    Par méphistopheles dans le forum Langage
    Réponses: 4
    Dernier message: 31/03/2007, 11h56

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