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 :

pointeur sur pointeur générique


Sujet :

C

  1. #1
    Membre régulier
    Inscrit en
    Avril 2005
    Messages
    156
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 156
    Points : 76
    Points
    76
    Par défaut pointeur sur pointeur générique
    Bonjour à tous,

    Comme vous le savez, il est possible de réaliser des affectations entre des pointeurs sur des objets et des pointeurs de type void * sans conversion explicite. Mais pourquoi n'en est-il pas de même avec les pointeurs de type void ** ?

    Par exemple, j'aimerais créer une fonction qui alloue de la mémoire pour une matrice et une autre qui libère la mémoire allouée pour une matrice :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void **matrix_create(<...>){
        void **m;
        /* allocation mémoire */
        return m;
    }
     
    void matrix_free(void **m){
        /* corps de la fonction */
    }
    Et pour les utiliser, je suis obligé de caster le retour de matrix_create et l'argument de matrix_free pour ne pas avoir de warning à la compilation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #include <stdlib.h>
     
    int main(void){
        int **m = (int **)matrix_create(<...>);
        /* traitement */
        matrix_free((void **)m);
        return EXIT_SUCCESS;
    }
    Pour éviter ces cast, peut-on (doit-on) définir les fonctions ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void *matrix_create(<...>){
        void **m;
        /* allocation mémoire pour m */
        return m;
    }
    (--> retour de type void * au lieu de void **)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void matrix_free(void *m){
        /* conversion pour pouvoir déréférencer le paramètre */
        void **mm = (void **)m;
        /* libération mémoire de mm */
    }
    (--> paramètre de type void * au lieu de void **)

    ?

  2. #2
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par j0o0 Voir le message
    Bonjour à tous,

    Comme vous le savez, il est possible de réaliser des affectations entre des pointeurs sur des objets et des pointeurs de type void * sans conversion explicite. Mais pourquoi n'en est-il pas de même avec les pointeurs de type void ** ?
    Parce que la valeur pointée par un pointeur void** est typée. C'est un pointeur sur un type void* et pas sur un type void (qui lui, est générique).
    Pas de Wi-Fi à la maison : CPL

  3. #3
    Membre régulier
    Inscrit en
    Avril 2005
    Messages
    156
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 156
    Points : 76
    Points
    76
    Par défaut
    Ah ok merci beaucoup !

    Et concernant la façon de coder les fonctions, la seconde proposition est-elle meilleure que la première (la conversion est faite à l'intérieur de la fonction, mais du coup le prototype est moins parlant : void * pour un tableau à deux dimensions...) ?

  4. #4
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par j0o0 Voir le message
    Et concernant la façon de coder les fonctions, la seconde proposition est-elle meilleure que la première (la conversion est faite à l'intérieur de la fonction, mais du coup le prototype est moins parlant : void * pour un tableau à deux dimensions...) ?
    C'est la seul façon de faire. En effet, dès qu'il a généricité, on perd des informations 'intrinsèques'. On doit compléter par des paramètres (taille, dimension, taille d'un élément etc.). Voir le prototype de qsort(). L'usage de void* est le seul possible. On passe une adresse, point.
    Pas de Wi-Fi à la maison : CPL

  5. #5
    Membre régulier
    Inscrit en
    Avril 2005
    Messages
    156
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 156
    Points : 76
    Points
    76
    Par défaut
    Merci pour toutes ces informations !

  6. #6
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par j0o0 Voir le message
    Bonjour à tous,

    Comme vous le savez, il est possible de réaliser des affectations entre des pointeurs sur des objets et des pointeurs de type void * sans conversion explicite. Mais pourquoi n'en est-il pas de même avec les pointeurs de type void ** ?
    Considere une machine ou sizeof(void*) != sizeof(int*) par exemple (ce qui est rare, mais autorise). Qu'est-ce qui se passe?
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  7. #7
    Membre régulier
    Inscrit en
    Avril 2005
    Messages
    156
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 156
    Points : 76
    Points
    76
    Par défaut
    Considere une machine ou sizeof(void*) != sizeof(int*) par exemple (ce qui est rare, mais autorise). Qu'est-ce qui se passe?
    J'ai beau y réfléchir, je ne vois pas. On a dépassé les limites de mes connaissances Mais j'aimerais vraiment que quelqu'un m'explique en détail ce qu'il se passe !

  8. #8
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    un void** pointe sur une zone memoire de taille differente que ce sur pointe un int**, donc ta creation de matrice a un probleme.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  9. #9
    Membre régulier
    Inscrit en
    Avril 2005
    Messages
    156
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 156
    Points : 76
    Points
    76
    Par défaut
    Voici le code complet des fonctions de création et destruction de matrice :

    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    #include <stdlib.h>
    #include <stddef.h>
     
    /* ---------------------------------------------------------------------
       UTILS_create_matrix : créé une matrice de nrows lignes et ncols colonnes
       initialisée à 0. size_row est la taille d'un pointeur vers un élément
       à stocker dans la matrice, size_col est la taille d'un élément. La
       mémoire utilisée est allouée avec malloc/calloc est doit être libérée
       avec free (ou free_matrix).
       ---------------------------------------------------------------------
       @param nrows : nombre de lignes de la matrice
       @param ncols : nombre de colonnes de la matrice
       @param p_elem_size : taille d'un pointeur vers un élément
       @param elem_size : taille d'un élément
       ---------------------------------------------------------------------
       @return : pointeur sur la matrice créée ou NULL en cas de mémoire
       insuffisante
       --------------------------------------------------------------------- */
    void *UTILS_create_matrix(size_t nrows, size_t ncols, size_t p_elem_size, size_t elem_size){
        void **m;
        if((m = malloc(nrows * p_elem_size)) != NULL){
            size_t i;
            for(i = 0; i < nrows; i++){
                if((m[i] = calloc(ncols, elem_size)) == NULL){
                    UTILS_free_matrix(m, i), m = NULL;
                    break;
                }
            }
        }
        return m;
    }
     
    /* ---------------------------------------------------------------------
       UTILS_free_matrix : libère la mémoire utilisée pour la matrice m.
       ---------------------------------------------------------------------
       @param m : adresse de la matrice à détruire
       @param n_p_elem : nombre de pointeurs vers éléments contenus dans la
       matrice
       --------------------------------------------------------------------- */
    void UTILS_free_matrix(void *m, size_t n_p_elem){
        if(m){
            size_t i;
            void **mat = (void **)m;
            for(i = 0; i < n_p_elem; i++){
                if(mat[i]){
                    free(mat[i]), mat[i] = NULL;
                }
            }
        }
    }
    Et un exemple d'utilisation :

    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
    #include <stdlib.h>
     
    #include "utils.h"
     
    #define NROWS 4
    #define NCOLS 3
     
    int main(void){
        int **m = UTILS_create_matrix(NROWS, NCOLS, sizeof(*m), sizeof(**m));
        if(m != NULL){
            // traitement
            UTILS_free_matrix(m, NROWS), m = NULL;
        }
        return 0;
    }
    Donc je pense que le problème auquel tu fais allusion n'apparaît pas ici, me trompe-je ?

  10. #10
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par j0o0 Voir le message
    Donc je pense que le problème auquel tu fais allusion n'apparaît pas ici, me trompe-je ?
    Non, mais il va vraisemblablement apparaître dans le traitement.

    (Mais bon, je ne suis pas un intégriste extrême: il y a toutes les chances que ca marche sur les plateformes auxquelles tu as accès.)
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  11. #11
    Membre régulier
    Inscrit en
    Avril 2005
    Messages
    156
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 156
    Points : 76
    Points
    76
    Par défaut
    Bon, désolé d'insister, je ne vois pas où peut se produire une erreur sur les machines où sizeof(void *) != sizeof(int *)

    Car dans :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int **m = UTILS_create_matrix(NROWS, NCOLS, sizeof(*m), size(**m));
    la fonction alloue d'abord de la mémoire pour des variables de type (int *), puis pour des variables de type (int), la mémoire est donc allouée en fonction du type voulu et peut-être ensuite utilisée correctement...

  12. #12
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par j0o0 Voir le message
    Bon, désolé d'insister, je ne vois pas où peut se produire une erreur sur les machines où sizeof(void *) != sizeof(void *)
    int* pas void*.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int **m = UTILS_create_matrix(NROWS, NCOLS, sizeof(*m), size(**m));
    la fonction alloue d'abord de la mémoire pour des variables de type (int *),
    Oui.

    puis pour des variables de type (int),
    Mais le resultat de cette allocation est stocke en tant que void* pas en tant que int*.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  13. #13
    Membre régulier
    Inscrit en
    Avril 2005
    Messages
    156
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 156
    Points : 76
    Points
    76
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    int* pas void*.
    Désolé, erreur d'inattention, je corrige.

    Merci, je crois avoir compris le problème, dans ce cas la seule solution portable à 100% serait-elle d'utiliser une macro-fonction :

    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
    #define INIT_MATRIX(m, nrows, ncols)  \
        do {\
            m = malloc(nrows * sizeof(*m));\
            if(m != NULL){\
                size_t i;\
                for(i = 0; i < nrows; i++){\
                    m[i] = calloc(ncols, sizeof(**m));\
                    if(m[i] == NULL){\
                        FREE_MATRIX(m, i);\
                        m = NULL;\
                        break;\
                    }\
                }\
            }\
        } while(0)
    ?

    En tout cas merci infiniment pour ton aide !

  14. #14
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par j0o0 Voir le message
    Merci, je crois avoir compris le problème, dans ce cas la seule solution portable à 100% serait-elle d'utiliser une macro-fonction :
    Si tu veux jouer avec les templates, apprends le C++...
    Pas de Wi-Fi à la maison : CPL

  15. #15
    Membre régulier
    Inscrit en
    Avril 2005
    Messages
    156
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 156
    Points : 76
    Points
    76
    Par défaut
    Citation Envoyé par Emmanuel Delahaye Voir le message
    Si tu veux jouer avec les templates, apprends le C++...
    C'est au programme Mais j'avais besoin de faire ceci en C.

Discussions similaires

  1. Pointeur sur pointeur
    Par Miko95 dans le forum C++
    Réponses: 25
    Dernier message: 03/01/2008, 13h25
  2. allocation et pointeur sur pointeur
    Par noobC dans le forum C
    Réponses: 7
    Dernier message: 13/11/2007, 19h00
  3. les pointeurs sur pointeurs ne m'aiment pas :/
    Par GhostNemo dans le forum C
    Réponses: 3
    Dernier message: 17/12/2006, 23h10
  4. Réponses: 6
    Dernier message: 02/11/2006, 16h44
  5. pointeur sur pointeur
    Par gaut dans le forum C
    Réponses: 3
    Dernier message: 01/11/2005, 21h30

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