Partage
  • Partager sur Facebook
  • Partager sur Twitter

Fonction fgets renvoie tout le contenu

Sujet résolu
    12 avril 2024 à 15:53:37

    Bonjour,

    Je suis actuellement en train de suivre le cours du langage C et je bute sur la fonction fgets.

    J'ai bien compris qu'elle lit ligne par ligne mais le concept du paramètre tailleMaximale m'échappe.

    Je vous explique :

    Je compile le code suivant :

    #include <stdio.h>
    #include <stdlib.h>
    
    #define TAILLE_MAX 1000
    
    int main(int argc, const char *argv[])
    {
        FILE *fichier=NULL;
        char c_ligne[10]="";
    
        // fichier = fopen("text.txt", "w");   // Ouverture pour écriture
        fichier = fopen("text.txt", "r");   // Ouverture pour lecture
    
        if(fichier!=NULL)
        {
            printf("Le fichier a bien ete ouvert !\n");
    
            while(fgets(c_ligne, 10, fichier)!=NULL)    // Lit ligne par ligne tout le fichier jusqu'à rencontrer un NULL qui indique la fin du fichier
            {
                printf("%s", c_ligne);
            }
    
            fclose(fichier);
        }
        else
        {
            printf("Le fichier ne s'est pas ouvert !\n");
        }
    
        
    
        return 0;
    }
    

    Voici le fichier text.txt :

    Hello bienvenue
    Salut voici un texte dans mon fichier
    Ceci est la seconde ligne du fichier
    C'est la dernière ligne du fichier

    De ce que je comprends, il est censé ouvrir le fichier "text.txt", et lire ligne par ligne maximum 10 caractères et m'afficher la chaîne de 10 caractères à chaque fois.

    Or quand je compile et exécute le code, bah il m'affiche tout le texte du fichier et pas seulement 10 caractères.

    Je ne saisis pas trop l'utilité de ce paramètre, mise à part qu'il doit être identique à la taille que j'ai déclaré pour mon tableau de char.

    J'ai testé en mettant une taille supérieure dans ma fonction par rapport à la taille du tableau et j'ai bien une erreur de segmentation.

    J'ai testé aussi avec une taille inférieure dans ma fonction par rapport à la taille du tableau et cela m'affiche toujours tout le texte.

    J'aimerai bien quelques avis éclairés, merci !

    -
    Edité par Terence01 15 avril 2024 à 14:49:52

    • Partager sur Facebook
    • Partager sur Twitter
      12 avril 2024 à 16:17:53

      Bonjour,

      fgets() est dans une boucle, il ne lit que 10 caractères puis lit les 10 suivants...

      • Partager sur Facebook
      • Partager sur Twitter

      En recherche d'emploi.

        12 avril 2024 à 16:24:01

        Ah ok, je pensais qu'on ne lisait uniquement que 10 caractères puis que la fonction passait à la prochaine ligne oubliant tout ce qui restait sur la ligne.

        Merci de l'éclaircissement !

        • Partager sur Facebook
        • Partager sur Twitter
          12 avril 2024 à 17:51:15

          Je te suggère d'insérer dans la boucle juste après le printf un autre printf du style:

                  printf("<>\n");

          Tu verras ce qui est lu à chaque appel à fgets.

          • Partager sur Facebook
          • Partager sur Twitter

          Le Tout est souvent plus grand que la somme de ses parties.

            12 avril 2024 à 17:58:56

            C'est exactement ce que j'ai fait, ça a été tout de suite plus clair :)

            Merci du tuyau.

            • Partager sur Facebook
            • Partager sur Twitter
              12 avril 2024 à 18:40:58

              Hello,

              Attention que fgets(c_line, 10, fichier); ne lit qu'au plus 10-1 caractères, de manière à pouvoir mettre un '\0' à la fin sans faire de débordement (source <-- en anglais)

              Edit: orthographe

              -
              Edité par edgarjacobs 12 avril 2024 à 23:38:46

              • Partager sur Facebook
              • Partager sur Twitter

              On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

                15 avril 2024 à 14:46:13

                Hello,

                Me voilà de retour encore avec cette fonction.

                J'ai continué le cours et dans le chapitre de la saisie sécurisée de texte, la fonction est réutilisée avec stdin cette-fois-ci.

                J'ai voulu tester pour voir de mettre le second paramètre "num" plus grand que la taille de mon tableau (Imaginons dans le cas où mon tableau et ce paramètre ne soient plus identiques)

                Jai donc fait ça :

                #include <stdio.h>
                #include <stdlib.h>
                
                int main(int argc, const char *agrv[])
                {
                    char nom[8]={0};
                
                    printf("Quel est votre nom ?\n");
                    fgets(nom, 15, stdin);
                
                    printf("Vous vous appelez donc %s\n", nom);
                    printf("%d\n", sizeof(nom));
                    
                    
                    return 0;
                }


                Lorsque je tape un prénom + nom de plu de 15 caractères, pas de problème, la fonction me renvoie bien 15 caractères (ligne 3 de la photo), j'affiche le tableau "nom" mais dedans il y a le contenu de stdin si j'ai bien compris.

                Mais quand je regarde la taille de mon tableau, il est toujours d'une taille de 8.

                Et si j'affiche l'entièreté de mon tableau, alors j'ai un texte de 15 caractères qui apparaît et pas seulement 8 (-1 caractère pour le caractère de fin de chaîne)

                Ma question est : que se passe-t-il au niveau de ce tableau ? Ai-je fait un dépassement de mémoire, mon tableau a-t-il changé de taille (Normalement non) ? Pourquoi il n'enregistre et n'affiche pas seulement 8 caractères comme défini au début ?

                • Partager sur Facebook
                • Partager sur Twitter
                  15 avril 2024 à 16:48:27

                  Ton tableau a une taille de 8 qui ne changera pas.

                  Toi tu y écris plus de 8 caractères, ça va donc écrire les caractères suivant à la suite en dehors de ton tableau. C'est ce qu'on appelle un UB (undefined behavior). Et la tout peux ce passer, un plantage de ton programme, des comportements étranges , comme rien du tout.

                  Il ne faut donc jamais écrire en dehors d'un tableau !

                  Terence01 a écrit:

                  Pourquoi il n'enregistre et n'affiche pas seulement 8 caractères comme défini au début ?

                  Tu dis a fgets d'écrire 15 caractères (s'il y a) il en écrit 15. fgets ne connait pas la taille du tableau.



                  • Partager sur Facebook
                  • Partager sur Twitter
                  ...
                    15 avril 2024 à 17:00:05

                    Ok merci de l'info, donc on on peut déborder si on ne fait pas attention, il faut toujours faire correspondre la taille du tableau avec la longueur qu'on récupère pour le 2nd paramètre si je comprends bien (par mesure de sécurité).

                    Donc le mieux serait de passer tout le temps en paramètre la taille de mon tableau avec un sizeof(nom) par exemple ?

                    • Partager sur Facebook
                    • Partager sur Twitter
                      15 avril 2024 à 17:28:39

                      Terence01 a écrit:

                      Donc le mieux serait de passer tout le temps en paramètre la taille de mon tableau avec un sizeof(nom) par exemple ?

                      Quand je dois utiliser fgets(), c'est ce que je fais.

                      • Partager sur Facebook
                      • Partager sur Twitter

                      On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

                        15 avril 2024 à 18:06:07

                        D'accord, merci pour la réponse !

                        Je me replonge dans le C après 4/5 ans sans en avoir fait depuis l'école donc désolé si c'est des questions un peu bêtes :D

                        • Partager sur Facebook
                        • Partager sur Twitter
                          15 avril 2024 à 19:29:04

                          Un exemple de comportement étrange comme l'écrit @rouloude

                          #include <stdio.h>
                          
                          int main(void) {
                          	int a[]={1,2,3,4,5};
                          	char nom[8]={0};
                          
                          	printf("a=");
                          	for(int i=0; i<5; i++)
                          		printf(" %d", a[i]);
                          	puts("");
                          	printf("Quel est votre nom ?\n");
                          	fgets(nom, 27, stdin);
                          	printf("Vous vous appelez donc %s\n", nom);
                          	printf("a=");
                          	for(int i=0; i<5; i++)
                          		printf(" %d", a[i]);
                          	puts("");
                          
                              return 0;
                          }

                          et tu entres les 26 lettres de l'alphabet.

                          -
                          Edité par edgarjacobs 15 avril 2024 à 19:31:50

                          • Partager sur Facebook
                          • Partager sur Twitter

                          On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

                            16 avril 2024 à 10:48:32

                            Je viens de tester, en effet comportement étrange.

                            nom prend toutes les valeurs de l'alphabet mais a débordé dans le tableau "a", donc on voit les valeurs à la suite dans le tableau.

                            Merci pour l'exemple !

                            • Partager sur Facebook
                            • Partager sur Twitter
                              16 avril 2024 à 18:00:58

                              Petite précision que j'ai omise dans ma réponse:

                              Terence01 a écrit:

                              Donc le mieux serait de passer tout le temps en paramètre la taille de mon tableau avec un sizeof(nom) par exemple ?


                              Attention que ce code ne fonctionnera pas comme on pourrait le penser
                              void GetDate(char str_data[31]) {
                              	fgets(str_data, sizeof(str_data), stdin);
                              	....
                              }
                              
                              
                              
                              int main(void) {
                              	char str[31];
                              	
                              	GetData(str);
                              	
                              	....
                              
                              }

                              L'erreur, c'est que str_data est un pointeur, et non un tableau de caractères. Donc le sizeof(str_data) renverra la taille d'un pointeur (4 ou 8 octets), et non le 31 espéré.

                              -
                              Edité par edgarjacobs 22 avril 2024 à 19:37:22

                              • Partager sur Facebook
                              • Partager sur Twitter

                              On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

                                16 avril 2024 à 18:22:33

                                Ok donc si un pointeur est passé en paramètre de fgets, pas de sizeof().

                                Il y a un moyen de contourner ça simplement ? ou alors mettre 31 ici dans ce code sera la meilleure chose à faire ?

                                J'ai testé les 2 cas de sizeof pour voir les valeurs retournées :

                                sizeof(str_data) => 8 octets

                                sizeof(*str_data) => 1 octet (logique c'est un char)

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  16 avril 2024 à 19:21:39

                                  Terence01 a écrit:

                                  [....] ou alors mettre 31 ici dans ce code sera la meilleure chose à faire ?

                                  Il faut absolument éviter les "nombres magiques" (ceux qui sont codés en dur dans le code). Bon, moi je l'ai fait, car ce n'est qu'un code de démonstration.

                                  Pour "contourner" le problème, il y a le bon vieux #define:

                                  #define STR_SIZE	31
                                  
                                  void GetData(char *str_data) {
                                      fgets(str_data, STR_SIZE, stdin);
                                      ....
                                  }
                                  
                                  int main(void) {
                                      char str[STR_SIZE];
                                  
                                      GetData(str);
                                      ....
                                  
                                  }

                                  C'est propre. Et si tu veux changer la taille de la variable, pas besoin de relire tout le code, au risque d'oublier une occurence du 31 ou d'en modifier une qui n'en avait pas besoin: il suffit de modifier le #define et de recompiler. Et les #define, on peut en utiliser à foison.

                                  Edit: edit supprimé, pas d'intérêt ici

                                  -
                                  Edité par edgarjacobs 16 avril 2024 à 20:59:12

                                  • Partager sur Facebook
                                  • Partager sur Twitter

                                  On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

                                    16 avril 2024 à 19:47:19

                                    Quand j'utilise des tableaux en C (de taille fixe), j'ai besoin de deux tailles :

                                    − la taille du tableau à sa déclaration, c'est-à-dire la zone mémoire maximale utilisable : c'est un #define ;

                                    − le nombre d'éléments utilisés dans le tableau, c'est-à-dire la zone mémoire réellement utilisée : c'est une variable.

                                    Exemple : un tableau de notes.

                                    /* Déclarations */
                                    #define MAXNBNOTES 100       // nombre maxi de notes possibles
                                    float tabnotes[MAXNBNOTES];  // le tableau
                                    int nbnotes = 0;             // nombre de notes saisies
                                                                 // (sera modifié plus loin)
                                    
                                    /* Appel à la fonction moyenne */
                                    float moyenne = fmoyenne(tabnotes, nbnotes);
                                    
                                    /* Fonction moyenne */
                                    float fmoyenne(float ftableau[], int nbelem) // j'ai mis un 'f' pour me souvenir
                                    {                                            // que c'est un tableau de float
                                        for (int i = 0 ; i < nbelem ; i++)
                                        {  /* traitement des éléments du tableau */  }
                                    }

                                    L'opérateur 'sizeof' fournirait la taille complète du tableau, ce n'est pas forcément celle qui nous intéresse.

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      19 avril 2024 à 15:04:35

                                      Salut,

                                      Merci pour l'exemple, toujours intéressant de voir du code.

                                      Ce que je note, c'est qu'il faudrait par exemple, vérifier que nbnotes est bien inférieur à la taille du tableau avant de le passer en paramètre, histoire de ne pas avoir de problèmes.

                                      -
                                      Edité par Terence01 19 avril 2024 à 15:04:50

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        19 avril 2024 à 17:38:38

                                        Terence01 a écrit:

                                        [....] Ce que je note, c'est qu'il faudrait par exemple, vérifier que nbnotes est bien inférieur à la taille du tableau avant de le passer en paramètre [....]

                                        Pas à mon avis. C'est au moment du remplissage du tableau qu'il faut faire cette vérification. Dans l'exemple de @robun, on peut facilement imaginer que le tableau de notes est rempli via stdin, c'est donc à ce moment-là que la vérification doit être faite.

                                        • Partager sur Facebook
                                        • Partager sur Twitter

                                        On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

                                          19 avril 2024 à 21:16:26

                                          De mon point de vue, je dirais qu'un tableau peut être modifié ou consulté (à chaque fois par une fonction dédiée).

                                          − Lorsqu'il est modifié, la taille peut varier, il faut la contrôler. C'est ce qu'on fera dans la fonction de saisie des éléments, ou la fonction d'ajout/suppression d'éléments, ou de copie du tableau dans un autre, ou de concaténation de deux tableaux, etc.

                                          − Lorsqu'il est consulté, on ne le me modifie pas, sa taille reste inchangée. Du fait de ce qui précède, le tableau est donc à la bonne taille, pas besoin de la contrôler. C'est le cas pour la fonction qui calcule la moyenne. (Du coup il faut peut-être ajouter un 'const' dans la définition ?)

                                          -
                                          Edité par robun 19 avril 2024 à 21:17:00

                                          • Partager sur Facebook
                                          • Partager sur Twitter

                                          Fonction fgets renvoie tout le contenu

                                          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                          • Editeur
                                          • Markdown