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 :

free d'un tableau dont l'adresse est passée en paramètre à une fonction


Sujet :

C

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    124
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 124
    Points : 86
    Points
    86
    Par défaut free d'un tableau dont l'adresse est passée en paramètre à une fonction
    Bonjour,

    J'ai cherché longtemps une solution à ce problème mais je ne trouve aucune solution. J'ai un tableau 2D de type char**. Je dois le stocker dans un char data[1] qui se trouve dans une structure.

    Mon objectif est de faire une fonction dans un main qui détruit ce tableau 2D.

    La structure du programme est comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    /*fichier1.h*/
    typedef struct {
           char data[1];
    } laStructure;
    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
    /*main.c*/
    void delete(void* data);
    char** creation_tableau (unsigned int nbLignes, unsigned int nbColonnes, char* valeurs);
     
    int main {
        char valeurs[12] = {'a','b','c','d','e','f','g','h','i','j','k','l'};
        char** t1 = creation_tableau (3, 4, valeurs);
        char* pT1 = &t1[0][0];
     
        laStructure* s1 = malloc(sizeof(laStructure));
        memcpy (s1->data, pT1, sizeof(pT1));
     
        delete (s1->data);
    }
     
    void delete(void* data) {
           // Je ne sais pas comment faire
    }
     
    char** creation_tableau (unsigned int nbLignes, unsigned int nbColonnes, char* valeurs) {
        char** tableau = (char**)malloc(sizeof(char*) * nbColonnes);
     
        unsigned int i;
        for (i=0 ; i<nbColonnes ; i++) {
            tableau[i] = (char*)malloc(sizeof(char) * nbLignes);
        }
     
        if (!tableau) { return NULL; }
     
        unsigned int j;
        for (j=0 ; j<nbLignes ; j++) {
            for (i=0 ; i<nbColonnes ; i++) {
                tableau[i][j] = valeurs[i+j*nbColonnes];
            }
        }
     
        return tableau;
    }
    Je ne sais pas comment faire ma fonction delete() pour qu'elle fasse un free du tableau.

  2. #2
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    void delete(void* data) {
           // Je ne sais pas comment faire
    Tu ne peux pas en l'état : Tu devrais commencer par faire autant de free() que tu as fais de malloc() pour remplir le tableau de pointeurs (autrement dit nbColonnes free() des tableau[ i] en se référant aux symboles utilisées dans creation_tableau ()). Et tu ne connais plus le nombre de free() à faire.

    On a les possibilités :

    1- stocker quelque part les dimensions du tableau créé, au moins nbColonnes, et le passer à la fonction. Par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    typedef struct
    {
       char** tab;
       int nbLignes;
       int nbColonnes;
    } Tableau;
    2- Placer une sentinelle dans le tableau, par exemple en ajoutant un pointeur NULL en fin du tableau (qui jouera un rôle analogue à '\0' pour les chaines de caractères)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        char** tableau = malloc(sizeof(char*) * (nbColonnes+1));
        for (i=0 ; i<nbColonnes ; i++) {
            tableau[i] = malloc(nbLignes);
        }
       tableau[i] = NULL;
    3- Utiliser un nombre fixe de malloc(), donc allouer un bloc continu pour les char.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
       char** tableau = malloc(sizeof(char*) * nbColonnes);
        tableau[0] = malloc(nbColonnes*nbLignes);
        for (i=1 ; i<nbColonnes ; i++) {
            tableau[i] = tableau[i-1] + nbLignes;
        }
    Notes :

    1- Ton code, et les exemples brefs présentés ci-dessus, ne testent pas correctement les erreurs d'allocations. Notamment :
    -if (!tableau) { return NULL; } Le programme aura déjà planté avant sur tableau[i] si tableau == NULL
    - les allocations tableau[i]= malloc(...) ne sont pas testées.

    2-
    J'ai un tableau 2D de type char**. Je dois le stocker dans un char data[1]
    Précise ce que tu veux faire, car dit comme cela ce n'est pas possible (et ton code n'éclaire pas la situation)

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    124
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 124
    Points : 86
    Points
    86
    Par défaut
    Merci pour ta réponse diogene !

    Pour commencer, je ne peux pas modifier la structure.

    Citation Envoyé par diogene Voir le message
    2-
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    J'ai un tableau 2D de type char**. Je dois le stocker dans un char data[1]
    Précise ce que tu veux faire, car dit comme cela ce n'est pas possible (et ton code n'éclaire pas la situation)
    En effet, je ne stocke pas le tableau dans le char data[1]. data pointe sur le premier élément du tableau 2D, si j'ai bien compris. Je n'ai jamais utilisé cette méthode.

    Citation Envoyé par diogene Voir le message
    On a les possibilités :

    1- stocker quelque part les dimensions du tableau créé, au moins nbColonnes, et le passer à la fonction. Par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    typedef struct
    {
       char** tab;
       int nbLignes;
       int nbColonnes;
    } Tableau;
    2- Placer une sentinelle dans le tableau, par exemple en ajoutant un pointeur NULL en fin du tableau (qui jouera un rôle analogue à '\0' pour les chaines de caractères)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        char** tableau = malloc(sizeof(char*) * (nbColonnes+1));
        for (i=0 ; i<nbColonnes ; i++) {
            tableau[i] = malloc(nbLignes);
        }
       tableau[i] = NULL;
    3- Utiliser un nombre fixe de malloc(), donc allouer un bloc continu pour les char.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
       char** tableau = malloc(sizeof(char*) * nbColonnes);
        tableau[0] = malloc(nbColonnes*nbLignes);
        for (i=1 ; i<nbColonnes ; i++) {
            tableau[i] = tableau[i-1] + nbLignes;
        }
    Je ne sais pas encore comment je vais faire pour la taille du tableau. Je vais surement partir sur une taille fixe. Mais ce n'est pas mon problème principal.

    Mon problème actuellement est que je n'arrive pas à faire un free() qui ne plante pas. Que ce soit sur une ligne ou le tableau entier.
    J'ai essayé plusieurs méthodes pour la fonction delete(), mais aucune ne mache :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    void delete (void* data) {
        char* pTableau = (char*)data;
     
        int i;
        for (i=0 ; i<3 ; i++) {
            free(pTableau+i);
        }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    void delete (void* data) {
        char* pTableau = (char*)data;
     
        int i;
        for (i=0 ; i<3 ; i++) {
            free(pTableau[i]);
        }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void delete (void* data) {
        free((char*)data);
    }

  4. #4
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Non, le problème de delete() est seulement dans la dimension.
    Par contre, l'appel de delete() est important. Dans ton premier message, tu fais un delete (s1->data);or s1->data n'a pas été alloué par un malloc(), c'est s1 qui l'a été.

    Le code est partiellement incohérent :
    En effet, je ne stocke pas le tableau dans le char data[1]. data pointe sur le premier élément du tableau 2D, si j'ai bien compris. Je n'ai jamais utilisé cette méthode.
    Si on veut stocker une adresse, il faut un pointeur (du bon type), pas un tableau. Tu veux stocker l'adresse de quoi ? Pas du tableau des char puisque il n'y a pas UN tableau de char, de la façon dont tu l'as créé, mais nbColonnes tableaux de char. Du tableau (pseudo)2D que tu as créé ? Si oui, on doit avoir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    typedef struct {
           char ** data;
    } laStructure;
    Et on aurait quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        laStructure* s1 = malloc(sizeof(laStructure));
        if(s1!= NULL)
        {
          s1->data = creation_tableau (3, 4, valeurs);
          ....
          delete (s1->data);
          free(s1);
        }

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    124
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 124
    Points : 86
    Points
    86
    Par défaut
    Je ne sais pas pourquoi la structure a été crée avec un char data[1] étant donné qu'elle doit pointer vers un tableau 2D. J'aurais aussi utilisé un char** si je l'avais programmé.
    Toujours est il que je peux afficher le tableau grâce à data de cette manière :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int i, j;
    for (j=0 ; j<3 ; j++) {
        for (i=0 ; i<4 ; i++) {
            printf("%c", s1->data[j]+i);
        }
     
        printf("\t"); 
    }
    printf("\n");
    Mais par rapport à ce que tu me dis, je comprend qu'avec ce char data[1] je ne peux pas faire un free() du tableau créé dans le main (char** t1). Le code a pourtant été donnée comme ça, et malheureusement on peut trouver dans fichier1.c un delete(s1->data) alors que data est sensé pointer vers un tableau 2D.

    Par contre, dans mon exemple, le tableau t1 est bien créé avec des malloc. Voir le code creation_tableau() :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    char** tableau = (char**)malloc(sizeof(char*) * nbColonnes);
     
        unsigned int i;
        for (i=0 ; i<nbColonnes ; i++) {
            tableau[i] = (char*)malloc(sizeof(char) * nbLignes);
        }
    Je ne sais pas trop si je dois considérer que c'est une erreur dans le code fournie qui aurait mal été adapté. Et même si je n'aime pas ça, je vais devoir contourner le problème en modifiant la structure alors que je ne suis pas sensé le faire.

  6. #6
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Ce code ne fonctionne que par hasard et a un comportement non défini.
    - Dans la structure, la seule chose garantie est d'avoir de la place pour un char.
    Lorsqu'on écrit memcpy (s1->data, pT1, sizeof(pT1)); on va écrire dans ce char une adresse, donc à priori il n'y aura pas la place et on écrira aussi derrière la structure. Si ce qu'il y a derrière la structure laisse de la place libre, alors le bug peut ne pas avoir de conséquences visibles. Mais cela dépend de la taille d'un pointeur, des variables définies et de leur condition d'alignement utilisée par le compilateur.
    C'est évidemment à proscrire.

    -Lorsque tu écris ce code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int i, j;
    for (j=0 ; j<3 ; j++) {
        for (i=0 ; i<4 ; i++) {
            printf("%c", s1->data[j]+i);
        }
     
        printf("\t"); 
    }
    printf("\n");
    cela ne peut pas afficher les bonnes valeurs, essaye le avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char valeurs[12] = {'x','b','c','d','@','f','g','h','>','j','k','l'};

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    124
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 124
    Points : 86
    Points
    86
    Par défaut
    D'accord je comprend, merci pour cette aide précieuse en tout cas. Mais comment un prof peut fournir un tel code est expliquer que le char data[1] est un pointeur sur un tableau 2D ?! Je trouvais ça surprenant aussi... En tout cas ça manque clairement d'explication de sa part.

    Je vais pousser un petit coup de gueule inutile mais j'assume. Si on écoute certains prof, les élèves sont des fénéants qui essayent d'en faire le moins possible. Je remarque surtout, qu'à la FAC, on en demande toujours plus aux élèves qui doivent combler par du travail personnel toutes les lacunes de l'enseignement qui leur est donné.
    Mais tous les élèves ne sont pas logés à la même enseigne. Toutes les formations n'ont pas l'emploi du temps des élèves d'informatique. Il n'y a aucun discours entre les prof pour prendre en considération les conditions de travail des élèves. Les projets arrivent tous au même moment et s'ajoutent aux TP notés. Cette année les sujets d'exams de certaines UE ne seront traités en TP que le vendredi précédent l'épreuve, ou maximum une semaine avant.
    Les faux sondages fait sur l'appréciation des cours par les élèves ne sont jamais pris au sérieux. Les étudiants en informatique sont des passionnés, ils doivent avoir le loisir de faire de l'informatique 24h/24 7j/7.
    Au final, les TP et les projets sont bâclés par manque de temps et on dit adieu à l'enseignement qu'ils sont sensés nous apporter.
    Un autre truc pas mal dans le genre : on a eu des UE ou tous les TPs (traitable en 3h si on connait parfaitement le sujet) devaient être rendu à la fin des 3H. Résultat, le TP devient une course pour finir mais pas le temps d'apprendre. Mais quel est le rôle des TP alors ?
    Les informaticiens, on est vraiment de bonnes poires...

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

Discussions similaires

  1. [9i] Parcourir un tableau dont l'index est de type VARCHAR2
    Par weejungle dans le forum PL/SQL
    Réponses: 3
    Dernier message: 14/09/2013, 16h32
  2. somme des cellules dont l'adresse est contenue dans un tableau?
    Par mazuno dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 28/06/2010, 13h15
  3. Réponses: 7
    Dernier message: 27/05/2008, 10h54
  4. Réponses: 4
    Dernier message: 22/02/2007, 10h01
  5. longueur de tableau dont le nom est passé en paramètre
    Par max.onyx dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 09/06/2006, 19h54

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