Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème structure et tableau à double dimension

Sujet résolu
    4 juin 2021 à 23:37:58

    Bonsoir ! J'ai encore un petit soucis (décidement) .. Je dois donc Ecrire une fonction qui prend en parametre un tableau de chaine de caracteres ainsi que la taille de ce tableau et renvoie un tableau de structure : ft_strs_to_tab.

    Puis je dois écrire une autre fonction qui affiche le contenu d'un tableau créé par la fonction précédente : ft_show_tab.

    Et j'ai un header (t_stock_str) qui se présente comme ça :

    #ifndef FT_STOCK_STR_H
    # define FT_STOCK_STR_H
    
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    #include <time.h>
    #include <unistd.h>
    
    typedef struct s_stock_str
    {
        int size;
        char *str;
        char *copy;
    }              t_stock_str;
    
    
    #endif

    Donc j'ai mes deux fonctions (.c) qui ont l'air de marcher : 

    #include "ft_stock_str.h"
    
    void ft_show_tab(struct s_stock_str *par);
    
    int ft_strlen(char *str)
    {
        int i;
        
        i = 0;
        while(str[i])
        {
            i++;
        }
        return (i);
    }
    
    char *ft_strdup(char *src)
    {
        char *str;
        int i;
        
        str = malloc(sizeof(char) * ft_strlen(src) + 1); // on alloue le tab str pour pouvoir faire rentrer src dedans et +1 pour pouvoir ajouter le '\0' à la fin.
        
        i = 0;
        while(src[i])
        {
            str[i] = src[i];
            i++;
            
        }
        str[i] = '\0';
        
        return (str);
        
        
    }
    
    struct s_stock_str *ft_strs_to_tab(int ac, char **av)
    {
        t_stock_str *tab;
        int i;
        
        /*Ici on alloue le tableau stock_str avec le type t_stock_str (ça aurait pu etre char)
         qui est ici une coordonnées, on multiplie ça par la taille du tableau AV (= ac) + 1 car on a besoin d'une case en plus pour pouvoir finir par 0 comme demandé. Et le if ! --> On verifie l'allocation de memoire*/
        
        if(!(tab = malloc(sizeof(t_stock_str) * ac + 1)))
            return NULL;
        
        i = 0;
        while(i < ac)
        {
            tab[i].size = ft_strlen(av[i]);
            if(!(tab[i].str = malloc(sizeof(char) * ft_strlen(av[i]) + 1)))
                return (NULL);
            tab[i].str = av[i];
            if(!(tab[i].copy == malloc(sizeof(char) * ft_strlen(av[i]) + 1)))
                return (NULL);
            tab[i].copy = ft_strdup(av[i]);
            i++;
        }
        /*tab[i].size = 0;
        tab[i].str = 0;
        tab[i].copy = 0;*/
        return (tab);
        
    }
    #include "ft_stock_str.h"
    
    void ft_putstr(char *str)
    {
        int i;
        
        i = 0;
        while(str[i])
        {
            write(1, &str[i], 1);
            i++;
        }
    }
    
    void ft_putchar(char c)
    {
        write(1, &c, 1);
    }
    
    void ft_putnbr(int nb)
    {
        int n;
        n = nb;
    
        if (nb < 0)
        {
            n *= -1;
            ft_putchar('-');
        }
        
        if(n < 10)
        {
            ft_putchar(n + '0');
        }
        
        if(n > 9)
        {
            ft_putnbr(n / 10);
            ft_putnbr(n % 10);
        }
    }
    
    
    
    void ft_show_tab(struct s_stock_str *par)
    {
        int i;
    
        i = 0;
        while(par[i].str != 0)
        {
            ft_putstr(par[i].str);
            ft_putchar('\n');
            ft_putnbr(par[i].size);
            ft_putchar('\n');
            ft_putstr(par[i].copy);
            ft_putchar('\n');
            i++;
        }
    }



    Et du coup j'essaye de faire un main pour pouvoir vérifier mes fonctions mais avec ce main il y a un problème de thread à cette ligne : while(par[i].str != 0) dans la fonction ft_show_tab.

    Est ce que quelqu'un peut m'aider j'ai vraiment l'impression de ne pas avoir fait de fautes sur mes fonctions (Mais bon je dois en avoir une quelque part haha..) Merciii !

    struct s_stock_str    *ft_strs_to_tab(int ac, char **av);
    void                ft_show_tab(struct s_stock_str *par);
    
    
    int                    main(void)
    {
     
        char* strs[3] = {"hey", "hello" , "hola"};
        int size = 3;
            
        
        ft_show_tab(ft_strs_to_tab(size, strs));
    }



    -
    Edité par NoéDormoy 4 juin 2021 à 23:39:29

    • Partager sur Facebook
    • Partager sur Twitter
      5 juin 2021 à 0:15:07

      Dans ta fonction ft_strs_to_tab ligne 56 tu as mis == au lieu de =

      Aussi, dans la même fonction : tu alloues de la mémoire pour tab[i].str et un peu plus loin tu lui affectes une autre adresse, tu perd donc l'adresse de ton allocation ! IDEM pour tab[i].copy

      J'ai pas tout regardé, mais ça peut peut-être te débloquer.

      -
      Edité par rouloude 5 juin 2021 à 0:20:11

      • Partager sur Facebook
      • Partager sur Twitter
        5 juin 2021 à 8:03:53

        Alors je vais essayer de t'apprendre un super truc : débuguer par toi-même ce genre de problème.

        Étape 1 → la compilation en activant les flags de debug.

        hyper simple, on utilise le flag -g !

        $ gcc -g -Wall -Wextra -o main main.c

        Oui, j'ai mis tout ton code dans un fichier que j'ai nommé main,

        Étape 2 → On voit que ça segfault alors avant le debuger on essaye valgrind

        Et là on obtient ce log :

        $ valgrind --leak-check=full --track-origins=yes --show-reachable=yes ./main
        ==134050== Memcheck, a memory error detector
        ==134050== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
        ==134050== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
        ==134050== Command: ./main
        ==134050== 
        ==134050== Conditional jump or move depends on uninitialised value(s)
        ==134050==    at 0x109382: ft_strs_to_tab (main.c:56)
        ==134050==    by 0x109623: main (main.c:138)
        ==134050==  Uninitialised value was created by a heap allocation
        ==134050==    at 0x483E7C5: malloc (vg_replace_malloc.c:380)
        ==134050==    by 0x109235: ft_strs_to_tab (main.c:46)
        ==134050==    by 0x109623: main (main.c:138)
        ==134050== 
        ==134050== Invalid read of size 8
        ==134050==    at 0x1095C3: ft_show_tab (main.c:115)
        ==134050==    by 0x10962B: main (main.c:138)
        ==134050==  Address 0x8 is not stack'd, malloc'd or (recently) free'd
        ==134050== 
        ==134050== 
        ==134050== Process terminating with default action of signal 11 (SIGSEGV): dumping core
        ==134050==  Access not within mapped region at address 0x8
        ==134050==    at 0x1095C3: ft_show_tab (main.c:115)
        ==134050==    by 0x10962B: main (main.c:138)
        

        Et le premier gros pavé correspond à ce que Rouloude a détecté.

        Voilà comment on trouve une partie des erreurs en moins de 5 minutes avec valgrind au lieu de plus d'une heure (ou plus) en posant une question sur un forum.



        • Partager sur Facebook
        • Partager sur Twitter
          5 juin 2021 à 14:07:02

          rouloude a écrit:

          Dans ta fonction ft_strs_to_tab ligne 56 tu as mis == au lieu de =

          Aussi, dans la même fonction : tu alloues de la mémoire pour tab[i].str et un peu plus loin tu lui affectes une autre adresse, tu perd donc l'adresse de ton allocation ! IDEM pour tab[i].copy

          J'ai pas tout regardé, mais ça peut peut-être te débloquer.

          -
          Edité par rouloude il y a environ 13 heures

          Merci !!!! c'était bien le == qui faisait planter le programme !

          White Crow a écrit:

          Alors je vais essayer de t'apprendre un super truc : débuguer par toi-même ce genre de problème.

          Étape 1 → la compilation en activant les flags de debug.

          hyper simple, on utilise le flag -g !

          $ gcc -g -Wall -Wextra -o main main.c

          Oui, j'ai mis tout ton code dans un fichier que j'ai nommé main,

          Étape 2 → On voit que ça segfault alors avant le debuger on essaye valgrind

          Et là on obtient ce log :

          $ valgrind --leak-check=full --track-origins=yes --show-reachable=yes ./main
          ==134050== Memcheck, a memory error detector
          ==134050== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
          ==134050== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
          ==134050== Command: ./main
          ==134050== 
          ==134050== Conditional jump or move depends on uninitialised value(s)
          ==134050==    at 0x109382: ft_strs_to_tab (main.c:56)
          ==134050==    by 0x109623: main (main.c:138)
          ==134050==  Uninitialised value was created by a heap allocation
          ==134050==    at 0x483E7C5: malloc (vg_replace_malloc.c:380)
          ==134050==    by 0x109235: ft_strs_to_tab (main.c:46)
          ==134050==    by 0x109623: main (main.c:138)
          ==134050== 
          ==134050== Invalid read of size 8
          ==134050==    at 0x1095C3: ft_show_tab (main.c:115)
          ==134050==    by 0x10962B: main (main.c:138)
          ==134050==  Address 0x8 is not stack'd, malloc'd or (recently) free'd
          ==134050== 
          ==134050== 
          ==134050== Process terminating with default action of signal 11 (SIGSEGV): dumping core
          ==134050==  Access not within mapped region at address 0x8
          ==134050==    at 0x1095C3: ft_show_tab (main.c:115)
          ==134050==    by 0x10962B: main (main.c:138)
          

          Et le premier gros pavé correspond à ce que Rouloude a détecté.

          Voilà comment on trouve une partie des erreurs en moins de 5 minutes avec valgrind au lieu de plus d'une heure (ou plus) en posant une question sur un forum.



          Merci beaucoup ! Mais je n'arrive pas à lire le valgrind, ça ne donne pas les erreurs par ligne ? 

          -
          Edité par NoéDormoy 5 juin 2021 à 14:13:24

          • Partager sur Facebook
          • Partager sur Twitter
            5 juin 2021 à 15:09:37

            Comment ça tu n'arrives pas à lire le log ?

            Tu as bien compilé avec le flag -g ? Tu sais, l'étape 1 …

            Ensuite tu as bien lancé l'exécutable avec valgrind comme je l'ai fait (tu as remarqué qu'il y a la ligne de commande non ? ) ? tu sais, l'étape 2 …

             Ensuite dans mon exemple tu vois bien qu'il te dit que il y a un souci à cause de l'utilisation d'une valeur non initialisée dans la fonction ft_strs_to_tab à la ligne  de mon ifchier main.c, fonction appelée dans main à la ligne 138 ⇒

            ==134050== Conditional jump or move depends on uninitialised value(s)
            ==134050==    at 0x109382: ft_strs_to_tab (main.c:56)
            ==134050==    by 0x109623: main (main.c:138)

            que cette valeur a été créée par une allocation dynamique par malloc dans la fonction ft_strs_to_tab en ligne 46 … ⇒

            ==134050==  Uninitialised value was created by a heap allocation
            ==134050==    at 0x483E7C5: malloc (vg_replace_malloc.c:380)
            ==134050==    by 0x109235: ft_strs_to_tab (main.c:46)
            ==134050==    by 0x109623: main (main.c:138)
            ==134050==

            Tu as quand même essayé de tout refaire non ?

            • Partager sur Facebook
            • Partager sur Twitter
              5 juin 2021 à 23:55:09

              White Crow a écrit:

              Comment ça tu n'arrives pas à lire le log ?

              Tu as bien compilé avec le flag -g ? Tu sais, l'étape 1 …

              Ensuite tu as bien lancé l'exécutable avec valgrind comme je l'ai fait (tu as remarqué qu'il y a la ligne de commande non ? ) ? tu sais, l'étape 2 …

               Ensuite dans mon exemple tu vois bien qu'il te dit que il y a un souci à cause de l'utilisation d'une valeur non initialisée dans la fonction ft_strs_to_tab à la ligne  de mon ifchier main.c, fonction appelée dans main à la ligne 138 ⇒

              ==134050== Conditional jump or move depends on uninitialised value(s)
              ==134050==    at 0x109382: ft_strs_to_tab (main.c:56)
              ==134050==    by 0x109623: main (main.c:138)

              que cette valeur a été créée par une allocation dynamique par malloc dans la fonction ft_strs_to_tab en ligne 46 … ⇒

              ==134050==  Uninitialised value was created by a heap allocation
              ==134050==    at 0x483E7C5: malloc (vg_replace_malloc.c:380)
              ==134050==    by 0x109235: ft_strs_to_tab (main.c:46)
              ==134050==    by 0x109623: main (main.c:138)
              ==134050==

              Tu as quand même essayé de tout refaire non ?

              Ah oui ça marche comme ça, pardon j'ai mal lu, c'est plus clair maintenant !!! :)

              • Partager sur Facebook
              • Partager sur Twitter
                6 juin 2021 à 0:01:30

                Cool :)

                L'étape d'après c'est apprendre à utiliser un debuger comme gdb … et là tu seras totalement autonome ! le pied quoi.

                • Partager sur Facebook
                • Partager sur Twitter
                  6 juin 2021 à 18:56:10

                  White Crow a écrit:

                  Cool :)

                  L'étape d'après c'est apprendre à utiliser un debuger comme gdb … et là tu seras totalement autonome ! le pied quoi.


                  Hahah oui j'ai hâte !! La lecture est un peu compliquée pour l'instant mais ça va venir ! Merci du conseil en tout cas !! :) 

                  • Partager sur Facebook
                  • Partager sur Twitter
                    7 juin 2021 à 12:14:38

                    NoéDormoy a écrit:

                    White Crow a écrit:

                    Cool :)

                    L'étape d'après c'est apprendre à utiliser un debuger comme gdb … et là tu seras totalement autonome ! le pied quoi.


                    Hahah oui j'ai hâte !! La lecture est un peu compliquée pour l'instant mais ça va venir ! Merci du conseil en tout cas !! :) 


                    Pour le débogage, tu peux faire toujours ta compilation avec le "-g" et ensuite utiliser l'utilitaire lldb.

                    Pour ce faire, si tu ne l'as pas, tu peux l'installer, et ensuite faire "lldb a.out" (si jamais tu n'as pas renommé on programme) et ça va t'afficher une fenêtre.

                    Une utilisation simple de lldb (sans les arguments argc) c'est de créer un breakpoint en écrivant "b main". Cela va créer un ancrage sur ta fonction main.

                    Puis ensuite d'exécuter à partir de ce point d'ancrage en écrivant "r".

                    Ensuite d'afficher le mode fenêtré en écrivant "gui" et te balader dans tes fonctions avec la touche "s" - qui permet de rentrer dans des fonctions que tu auras écrites toi même -, ou bien avec la touche "n", qui va te donner le résultat d'une fonction sans "rentrer" dedans.

                    Comme dit, c'est très très pratique, et ça permet de pouvoir comprendre ce qui pêche à un moment T. Par contre, je suis étonné que lors de la compilation tu n'aies pas eu un warning pour t'indiquer l'erreur entre "=" et "==".

                    Pour ce qui semble être une exercice de 42, en plus des flags que t'as mis WhiteCrow, je te conseille très fortement de faire :

                    gcc -g -Wall -Wextra -Werror mesfichiers.c
                    // Ou
                    clang -g -Wall -Wextra -Werror mesfichiers.c

                    Tous les warnings seront ainsi traités en erreurs, et donc la compilation ne se fera pas tant que tu n'auras pas réglé ce problème. C'est une obligation à 42 si tu souhaites rentrer dans cette école (si ce n'est déjà fait !). ;)

                    • Partager sur Facebook
                    • Partager sur Twitter
                      7 juin 2021 à 15:30:01

                      Batche a écrit:

                      NoéDormoy a écrit:

                      White Crow a écrit:

                      Cool :)

                      L'étape d'après c'est apprendre à utiliser un debuger comme gdb … et là tu seras totalement autonome ! le pied quoi.


                      Hahah oui j'ai hâte !! La lecture est un peu compliquée pour l'instant mais ça va venir ! Merci du conseil en tout cas !! :) 


                      Pour le débogage, tu peux faire toujours ta compilation avec le "-g" et ensuite utiliser l'utilitaire lldb.

                      Pour ce faire, si tu ne l'as pas, tu peux l'installer, et ensuite faire "lldb a.out" (si jamais tu n'as pas renommé on programme) et ça va t'afficher une fenêtre.

                      Une utilisation simple de lldb (sans les arguments argc) c'est de créer un breakpoint en écrivant "b main". Cela va créer un ancrage sur ta fonction main.

                      Puis ensuite d'exécuter à partir de ce point d'ancrage en écrivant "r".

                      Ensuite d'afficher le mode fenêtré en écrivant "gui" et te balader dans tes fonctions avec la touche "s" - qui permet de rentrer dans des fonctions que tu auras écrites toi même -, ou bien avec la touche "n", qui va te donner le résultat d'une fonction sans "rentrer" dedans.

                      Comme dit, c'est très très pratique, et ça permet de pouvoir comprendre ce qui pêche à un moment T. Par contre, je suis étonné que lors de la compilation tu n'aies pas eu un warning pour t'indiquer l'erreur entre "=" et "==".

                      Pour ce qui semble être une exercice de 42, en plus des flags que t'as mis WhiteCrow, je te conseille très fortement de faire :

                      gcc -g -Wall -Wextra -Werror mesfichiers.c
                      // Ou
                      clang -g -Wall -Wextra -Werror mesfichiers.c

                      Tous les warnings seront ainsi traités en erreurs, et donc la compilation ne se fera pas tant que tu n'auras pas réglé ce problème. C'est une obligation à 42 si tu souhaites rentrer dans cette école (si ce n'est déjà fait !). ;)

                      Super merci, je vais tester ça du coup !! Oui je vais passer la piscine en juillet :) ! C'est vrai que c'est bizarre mais l'erreur affichée n'était pas à la bonne ligne, ou j'ai loupé un truc haha ! 

                      • Partager sur Facebook
                      • Partager sur Twitter
                        9 juin 2021 à 9:38:38

                        Pour ce qui est de Valgrind l'erreur semble avoir été à la bonne ligne. D'ailleurs là c'est plus à cause du fait que tu n'as pas libéré la mémoire allouée pour tes structures. En piscine ce n'est pas gênant, mais si tu souhaites vraiment faire des trucs propres, libères la mémoire dans tes main (ou ailleurs, dans une fonction qui utilise la heap, donc une variable créée par malloc par exemple, et dont tu n'aurais plus besoin). Ce sera un automatisme vraiment très important pour la suite.

                        By the Way, en piscine tu ne pourras pas vraiment utiliser Valgrind il me semble, sauf s'ils passent sur des machines linux. Mais tu peux utiliser sanitizer. Ca fonctionne différemment, mais ça permet également de choper les leaks. Lldb c'est hyper pratique tu peux l'utiliser aussi en exam, ce qui est vraiment cool, notamment pour les exercices plus difficiles (aka ceux qui sont des petits programmes par exemple). Bon courage pour ta piscine en tout cas !

                        • Partager sur Facebook
                        • Partager sur Twitter
                          9 juin 2021 à 22:37:59

                          Batche a écrit:

                          Pour ce qui est de Valgrind l'erreur semble avoir été à la bonne ligne. D'ailleurs là c'est plus à cause du fait que tu n'as pas libéré la mémoire allouée pour tes structures. En piscine ce n'est pas gênant, mais si tu souhaites vraiment faire des trucs propres, libères la mémoire dans tes main (ou ailleurs, dans une fonction qui utilise la heap, donc une variable créée par malloc par exemple, et dont tu n'aurais plus besoin). Ce sera un automatisme vraiment très important pour la suite.

                          By the Way, en piscine tu ne pourras pas vraiment utiliser Valgrind il me semble, sauf s'ils passent sur des machines linux. Mais tu peux utiliser sanitizer. Ca fonctionne différemment, mais ça permet également de choper les leaks. Lldb c'est hyper pratique tu peux l'utiliser aussi en exam, ce qui est vraiment cool, notamment pour les exercices plus difficiles (aka ceux qui sont des petits programmes par exemple). Bon courage pour ta piscine en tout cas !


                          Oui c'est vrai j'ai pas libéré ma mémoire dans le main alors que j'aurais dû !! C'est parce que les main ne sont pas à rendre donc c'était juste pour voir si ça marchait du coup j'ai oublié, grosse erreur !! Ah mince... non ils sont sur mac avec mac os.. ! Ok il faut que j'aille me renseigner alors !! merci pour tout :) !
                          • Partager sur Facebook
                          • Partager sur Twitter

                          Problème structure et tableau à double dimension

                          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                          • Editeur
                          • Markdown