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 :

Comportement étrange d'un pointeur de pointeur de pointeur


Sujet :

C

  1. #1
    Futur Membre du Club
    Inscrit en
    Juin 2004
    Messages
    27
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 27
    Points : 7
    Points
    7
    Par défaut Comportement étrange d'un pointeur de pointeur de pointeur
    Bonjour,

    Je fais face à un comportement étrange, que je ne comprends pas.
    Je souhaite créer un tableau dynamique à 3 dimensions de la structure suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct point
    {
       float x, y, z, value;
    };
    Je cré un tableau de la taille suivante : [14][14][7]

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    struct point ***pts_base_field;
     
    pts_base_field=(float***) malloc (sizeof(float**) * 14 );
     
    for (i=0; i<=14; i++)
    	pts_base_field[i]=(float**) malloc (sizeof(float*) * 14 );
     
     
    for (i=0; i<=14; i++)
    	for (j=0; j<=14; j++)
    		pts_base_field[i][j]=(float*) malloc (sizeof(float) * 7 );
    Le problème, c'est que je peux accéder aux valeurs situées aux indices suivants :
    pts_base_field[14][14][9]


    Comment se fait-il ? Je ne vois pas où est le problème...
    Je vous remercie pour votre aide !

    Bonne journée !

    ++

  2. #2
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Points : 50 367
    Points
    50 367
    Par défaut
    Si tu créés un tableau [14][14][7], la dernière cellule de ce tableau a pour indice [13][13][6]. Les indices commence à 0 en C.

    Si tu tentes d'accéder à [14][14][7], tu es en dehors du tableau et tu fais n'importe quoi (récupération de valeur aléatoire ou bien crash du programme).
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  3. #3
    Futur Membre du Club
    Inscrit en
    Juin 2004
    Messages
    27
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 27
    Points : 7
    Points
    7
    Par défaut
    Merci pour ta réponse, je suis sur la bonne voie.

    Comment puis-je vérifier la taille de mon tableau ? J'ai de gros doutes sur les tailles des différentes dimensions.

  4. #4
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Points : 50 367
    Points
    50 367
    Par défaut
    C'est une des grosses limitations du C, tu ne peux pas demander à un tableau sa dimension.

    Soit le programme la connait (une variable, un define ou autre), soit le tableau est embarqué dans une structure un petit peu intelligente qui connait la taille du tableau qu'elle contient.
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  5. #5
    Futur Membre du Club
    Inscrit en
    Juin 2004
    Messages
    27
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 27
    Points : 7
    Points
    7
    Par défaut
    Merci pour l'info :-)

    J'ai un problème avec mes malloc je crois.
    Voici la création :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    pts_base_field=(float***) malloc (sizeof(float**) * (15) );
     
    for (i=0; i<15; i++)
    	pts_base_field[i]=(float**) malloc (sizeof(float*) * (15) );
     
    for (i=0; i<15; i++)
    	for (j=0; j<15; j++)
    		pts_base_field[i][j]=(float*) malloc (sizeof(float) * (8) );
    Ensuite, pour tester, je rempli le tableau de la sorte :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    for (i=0; i<15; i++)
    {
    	for (j=0; j<15; j++)
    	{
    		for (k=0; k<15; k++)
    		{
    			pts_base_field[i][j][k].x=i;
    			pts_base_field[i][j][k].y=j;
    			pts_base_field[i][j][k].z=k;
    		}
    	}
    }
    A la fin, si je consulte la variable "pts_base_field[0][0][6]", elle contient :
    x = 0
    y = 1
    z = 0

    Alors qu'elle devrait avoir :
    x = 0
    y = 0
    z = 6

    Le tableau m'a l'air tordu, non ?

  6. #6
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Points : 2 505
    Points
    2 505
    Par défaut
    Un tableau a plusieurs dimensions correspond toujours en mémoire à un seul bloc contigu. Pour allouer dynamiquement un tableau de ce type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Type array[sx][sy][sz];
    Il faut faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    array = mallo(sx * sy * sz * sizeof(Type));
    Et ainsi tu pourra l'accéder avec une syntaxe du type :

  7. #7
    Futur Membre du Club
    Inscrit en
    Juin 2004
    Messages
    27
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 27
    Points : 7
    Points
    7
    Par défaut
    Merci pour vos aides par contre, je ne vois pas comment faire l'allocation mémoire avec la dernière méthode donnée.
    Mon "Type" est toujours un float*** dans ce cas ?

    J'espère résoudre mon problème rapidement pour repartir sur des bases saines :-)

  8. #8
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Points : 2 505
    Points
    2 505
    Par défaut
    Non, Type est "struct point" dans ton cas, puisque tu veux un tableau à 3 dimensions de "struct point". D'ailleurs c'est une autre erreur que tu avais dans ton code initial : tu veux un tableau de struct point, mais tu allouais des cellules de la taille d'un char.

  9. #9
    Futur Membre du Club
    Inscrit en
    Juin 2004
    Messages
    27
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 27
    Points : 7
    Points
    7
    Par défaut
    Encore merci de passer un peu de temps pour me dépanner. Je cherche en parallèle comment m'en sortir car il s'agit d'un problème vraiment basique.

    Le code suivant ne fonctionne pas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    struct point
    {
       float x, y, z, value;
    };
     
    struct point ***test;
    test = malloc(14*14*7*sizeof(struct point));
    Est-ce que l'on est d'accord que la déclaration doit être la suivante :
    struct point ***test;

  10. #10
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Points : 2 505
    Points
    2 505
    Par défaut
    Si, c'est du C correct. D'ailleurs il compile sans problème. Qu'est-ce qui ne fonctionne pas ? Poste le code complet que tu as testé.

  11. #11
    Futur Membre du Club
    Inscrit en
    Juin 2004
    Messages
    27
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 27
    Points : 7
    Points
    7
    Par défaut
    Oui c'est du C.

    Voilà le code qui se compile mais ne fonctionne pas.

    La structure dans un fichier h est la suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct point
    {
       float x, y, z, value;
    };
    Le fichier c est le suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include "stdafx.h"
     
     
    int main(int argc, char *argv[], char *envp[])
    {
    	struct point ***test;
    	test = malloc(15*15*8*sizeof(struct point)) ;
     
    	test[0][0][0].x = 1;
    }

    Lors de l'execution de la dernière ligne, j'obtiens l'erreur suivante :
    Unhandled exception at 0x010a14e3 in test.exe: 0xC0000005: Access violation reading location 0xcdcdcdcd.

  12. #12
    Membre chevronné
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Points : 1 750
    Points
    1 750
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include "stdafx.h"
     
     
    int main(int argc, char *argv[], char *envp[])
    {
    	struct point ***test;
    	test = malloc(15*15*8*sizeof(struct point)) ;
     
    	test[0][0][0].x = 1;
    }
    Oui, c'est normal que ça plante.
    test est un pointeur de pointeur de pointeur sur point. Lorsque tu tapes :
    cela va provoquer 3 déréférencements successifs. Or, seul test contient une adresse valide.
    *test est un pointeur de pointeur sur point. Comme son contenu ne contient pas d'adresse valide, le déréférencement **test va provoquer un plantage.

  13. #13
    Futur Membre du Club
    Inscrit en
    Juin 2004
    Messages
    27
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 27
    Points : 7
    Points
    7
    Par défaut
    Merci pouir ton aide.

    Si j'ai bien compris, je réalise un adressage linéaire, qui me permet d'accéder à les données en 3 dimensions de cette facon là :
    Si je veux à tout prix accéder à mes données de la facon suivante :
    Je n'ai pas le choix, je vais devoir utiliser 3 malloc.

    Est-ce que j'ai juste ?

  14. #14
    Futur Membre du Club
    Inscrit en
    Juin 2004
    Messages
    27
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 27
    Points : 7
    Points
    7
    Par défaut
    En fait, je viens de découvrir un comportement que je ne le comprends pas.
    Ce code "fonctionne", pour pts_base_field[0][0][6], j'obtiens bien :
    x=0
    y=0
    z=6

    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
    struct point
    {
       float x, y, z;
    };
     
    struct point ***pts_base_field;
    pts_base_field=(float***) malloc (sizeof(float**) * 15 );
     
    for (i=0; i<15; i++)
    	pts_base_field[i]=(float**) malloc (sizeof(float*) * 15 );
     
    for (i=0; i<15; i++)
    	for (j=0; j<15; j++)
    		pts_base_field[i][j]=(float*) malloc (sizeof(float) * 8) );
     
    for (i=0; i<15; i++)
    {
    	for (j=0; j<15; j++)
    	{
    		for (k=0; k<8; k++)
    		{
    			pts_base_field[i][j][k].x=i;
    			pts_base_field[i][j][k].y=j;
    			pts_base_field[i][j][k].z=k;
    		}
    	}
    }
    Maintenant si je rajoute une variable dans la structure, sans toucher au code, celà ne marche plus, pour pts_base_field[0][0][6], j'obtiens :
    x=0
    y=1
    z=0

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct point
    {
       float x, y, z, value;
    };
    Quelqu'un peut m'expliquer ce comportement ?
    Encore merci pour votre aide, je galère là

  15. #15
    Futur Membre du Club
    Inscrit en
    Juin 2004
    Messages
    27
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 27
    Points : 7
    Points
    7
    Par défaut
    Stop, je suis un gros idiot.
    J'avais une sale erreur dans mes malloc.

    Je dois faire une allocation avec des "struct point" et non pas des "float"...

    Aie aie...

    En tout cas, merci pour votre aide, super rapide et efficace !!!


  16. #16
    Membre chevronné
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Points : 1 750
    Points
    1 750
    Par défaut
    Si j'ai bien compris, je réalise un adressage linéaire, qui me permet d'accéder à les données en 3 dimensions de cette facon là :
    Ca ne pourra pas fonctionner non plus.
    test[index] correspond à la même chose que *(test+index). Or si test est un pointeur de pointeur de pointeur sur point, tu peux peux pas accéder à x non plus vu que test[index] est alors un pointeur de pointeur sur point.

    Si tu veux utiliser des tableaux à 3 dimensions, je vois 3 solutions :

    1) Un réel tableau, au sens C. Mais si c'est un gros tableau, ça ne va pas du tout le faire (problème de taille).

    2) Un système de pointeur de pointeur de pointeur sur structure, comme tu fais actuellement.

    3) Un système à une seule dimension mais dont les index sont calculés de manière à simuler un système à 3 dimensions.
    Si par exemple tu as 3 dimensions dont la première a une taille de 10, la seconde de 50 et la troisième de 80, tu peux calculer l'index correspondant à la position de l'objet facilement via un calcul du style :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #define TAILLEX 10
    #define TAILLEY 50
    #define TAILLEZ 80
     
    struct structure *donnees=NULL;
    donnees=malloc(TAILLEX*TAILLEY*TAILLEZ*sizeof *donnees);
    if (donnees!=NULL)
    {
    (...)
    donnees[x+y*TAILLEX+z*TAILLEX*TAILLEY].membre=truc;
    (...)
    }
    où x,y,z correspondent respectivement aux index d'un système qui serait à 3 dimensions.

  17. #17
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Pour ce genre de choses, j'ai tendance à me limiter à une allocation par dimension. Comme ce message, mais avec un niveau de plus:
    http://www.developpez.net/forums/m1803870-7/
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  18. #18
    Futur Membre du Club
    Inscrit en
    Juin 2004
    Messages
    27
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 27
    Points : 7
    Points
    7
    Par défaut
    Ouha, que de réponses ! :-)

    Alors là je ne sais pas trop quelle méthode choisir, je vais tâcher d'expliquer facilement mon besoin. La réponse devrait être simple.

    Je dispose d'un nuage de point, qui forme une grille en 3 dimensions.
    Pour chaque point, je stocke les coordonnées cartésiennes (x, y, z) ainsi qu'une valeur (value).
    Ces grilles comptent plus de 30 000 points.

    Quand je manipule ces données, j'aimerais récupérer facilement tous les points qui sont à z=cte par exemple (x et y variant) ou encore tous les points à x et y constant (mais z variant).
    -> pour cette raison, la solution 3 de Jeroman ne me parait pas la plus simple, non ?

    Enfin, je souhaite que le code soit rapide, donc il faudrait limiter le nombre de malloc.
    -> pour cette raison, la structure de donnée que j'ai mise en place ne parait pas adaptée, non ?

    Est-ce que la solution idéale serait celle proposée par Médinoc ?
    J'avoue ne pas voir comment rajouter une autre dimension à sa technique et comment accéder aux données.


    En tout cas, merci pour tout !

  19. #19
    Expert éminent
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Points : 8 389
    Points
    8 389
    Par défaut
    Quand je manipule ces données, j'aimerais récupérer facilement tous les points qui sont à z=cte par exemple (x et y variant) ou encore tous les points à x et y constant (mais z variant).
    -> pour cette raison, la solution 3 de Jeroman ne me parait pas la plus simple, non ?
    Elle devient simple en ajoutant un define par exemple. Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #define DONNEES(x, y, z) donnees[(z) + (y) * TAILLEX + (x) * TAILLEX * TAILLEY]
     
    donnees = malloc(...);
     
    DONNEES(0, 0, 6) = ...

  20. #20
    Membre chevronné
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Points : 1 750
    Points
    1 750
    Par défaut
    En fait, tu veux créer/gérer une liste de 30000 points ou afficher ces points dans une grille à 3 dimensions ?

    Car si tu veux simplement repérer les points ayant par exemple un "z" à 100 (au pif), la méthode de création d'un tableau à 3 dimensions est sans intérêt et pas du tout rentable côté mémoire. Pour repérer les points ayant pour "z" une valeur spécifique, il suffit simplement de comparer avec cette valeur le membre "z" de chacun des 30000 points du tableau de structure.

    L'intérêt d'un tableau à 3 dimensions serait par exemple de quadriller des points en vue d'un affichage, etc.
    Or, si tu quadrilles tes points en 3 dimensions et que tu te sers de ce quadrillage pour effectuer des recherches de points, tu ne peux pas savoir à quel point correspond telle position x,y,z de la grille. De même, tu peux avoir 10 points qui se trouvent au même endroit dans la grille... voire aucun point.

    Après, tout dépend de ce que tu veux précisément faire dans ton projet.
    Mais s'il ne s'agit que de chercher des points dont les membres x,y ou z ont une valeur V ou une plage de valeurs comprise entre V1 et V2, le système à 3 dimensions n'est pas du tout justifié et il est à mon avis même déconseillé.

Discussions similaires

  1. problème pointeur comportement étrange
    Par all666 dans le forum Langage
    Réponses: 3
    Dernier message: 10/03/2015, 09h56
  2. comportement étrange d'une jointure ...
    Par amenis dans le forum PostgreSQL
    Réponses: 5
    Dernier message: 10/02/2005, 21h27
  3. Réponses: 10
    Dernier message: 03/02/2005, 13h09
  4. [Système][Runtime][Exec] Comportement étrange au lancement de BeSweet
    Par divxdede dans le forum API standards et tierces
    Réponses: 1
    Dernier message: 06/06/2004, 09h54
  5. Réponses: 2
    Dernier message: 22/09/2003, 11h23

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