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 :

[debutant] tableau 2 dimensions dynamique


Sujet :

C

  1. #1
    duj
    duj est déconnecté
    Membre confirmé

    Profil pro
    Inscrit en
    Juillet 2003
    Messages
    141
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juillet 2003
    Messages : 141
    Points : 474
    Points
    474
    Par défaut [debutant] tableau 2 dimensions dynamique
    Salut et merci d'avance de 'éclairer.
    voici mon code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
     
    struct RecordStruct{
    	char **pieces;
    };
     
    typedef struct RecordStruct record ;
     
    Record *newRecord(int size){
    	Record * r = (Record *) malloc(sizeof(Record));
    	r->pieces=(char **) malloc(sizeof(char)*size*50);
     
    	return r;
    }
    mon problème :
    d'après ce que j'ai lu ds la FAQ
    ds le code , ci dessous, pieces ne revient il pas à un tableau de char de size sur 50 ( char[size][50])? parceque quand, plus tard, j'éssaye d'y mettre des chaines de char, ca plante (à la troisième iteration) ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    int size = 12;
    Record *rc = newRecord(size);
    	char* word = (char *)malloc(sizeof(char));
    	char** array = rc->pieces;
    	int s;
    	for(s=0;size<size;s++){
    		getword(word,50);
     
    		strcpy(*array ,word);
    		array++;
     
    	}
    si j'ajoute cette ligne, ça passe,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    *array = (char * )malloc(sizeof(char)*50);
    mais c'est pas logique je pense, vu la faq
    http://lfe.developpez.com/FAQ/C/?pag...bleau_2D_alloc
    Parfois, Google fait des miracles

  2. #2
    Membre du Club

    Inscrit en
    Mai 2003
    Messages
    39
    Détails du profil
    Informations forums :
    Inscription : Mai 2003
    Messages : 39
    Points : 67
    Points
    67
    Par défaut
    Tu as un pb de représentation de la mémoire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char** array = malloc(sizeof(char)*size*50);
    Ce code fait que array pointe vers une zone mémoire de 50*size octets, ce qui veut dire que tu alloues de la place pour stocker ((50*size)/sizeof(char*)) pointeurs char :


    array pointe sur :

    ---------------------------------------------------------------------------------------------------------------------------------------
    | array[0] | array[1] | array[2] | array[3] | .... | array[((50*size)/sizeof(char*))-1] (cet élément est le dernier)
    ---------------------------------------------------------------------------------------------------------------------------------------

    maintenant, si on considère array[0] comme un pointeur... ben il pointe vers une zone indéfinie. Son allocation ne s'est faite nulle part.
    tout comme array[1], array[2].
    Donc toute écriture sur array[0][0], array[1][18], et plus généralement array[x][x] peut provoquer un plantage.

    Il faut faire une boucle pour allouer tes pointeurs 1 par 1.

  3. #3
    duj
    duj est déconnecté
    Membre confirmé

    Profil pro
    Inscrit en
    Juillet 2003
    Messages
    141
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juillet 2003
    Messages : 141
    Points : 474
    Points
    474
    Par défaut
    Ce que tu dis me semble logique et c'est pourquoi ma petite ligne en plus régle le problème.

    Je m'interroge donc du la methode 2 de la fac : dans quel cas peut-on l'utiliser?

    Si on désire allouer un tableau de N * M élements, il y a 2 méthodes possibles :
    on peut soit allouer un tableau de N élements et ensuite allouer dans chacun de ces éléménts, les M éléments nécessaires.
    ou alors on peut allouer en une seule fois la totalité du tableau


    A noter que si le tableau n'a pas le même nombre d'élements dans chacune des lignes, seule la première solution est utilisable.

    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
     
    char **tab;
     
    /* METHODE 1 */
    /* Allocation de la 1er dimension */
    tab = (char **) malloc ( sizeof (char *) * taille); 
     
    /* Allocation des tableaux */
    for (i=0; i<taille; i++) {
        tab[i] = (char *) malloc ( sizeof (char ) * taille2);
     
    } 
     
    /* METHODE 2*/
    tab = (char **) malloc ( sizeof (char ) * taille * taille2);
    Parfois, Google fait des miracles

  4. #4
    Membre actif
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    258
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2003
    Messages : 258
    Points : 288
    Points
    288
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    //On va créé un tableau de Var[50][25] comme exemple :
    char ** Var;
    int size = 50;
    int nb   = 25;
    int i = 0;
    int j = 0;
    Var = (char **)malloc(size * sizeof(char));
    while(i++ < size)
    {
         Var[i] = (char *)malloc(nb * sizeof(char));
    }
    Voilà

  5. #5
    Membre du Club

    Inscrit en
    Mai 2003
    Messages
    39
    Détails du profil
    Informations forums :
    Inscription : Mai 2003
    Messages : 39
    Points : 67
    Points
    67
    Par défaut
    Citation Envoyé par duj
    Ce que tu dis me semble logique et c'est pourquoi ma petite ligne en plus régle le problème.

    Je m'interroge donc du la methode 2 de la fac : dans quel cas peut-on l'utiliser?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    (...)
     
    /* METHODE 2*/
    tab = (char **) malloc ( sizeof (char ) * taille * taille2);
    Ce code n'est pas entier.
    Il faut faire les affectations d'adresse.
    edit : suppression de choses complètement fausses

  6. #6
    Membre du Club

    Inscrit en
    Mai 2003
    Messages
    39
    Détails du profil
    Informations forums :
    Inscription : Mai 2003
    Messages : 39
    Points : 67
    Points
    67
    Par défaut
    Citation Envoyé par duj
    Ce que tu dis me semble logique et c'est pourquoi ma petite ligne en plus régle le problème.
    FAUX !
    Le pointeur d'index 0 devient valide mais pas les autres :
    Il faut faire ne boucle comme te le montre Yabo sauf que son code est faux.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //On va créé un tableau de Var[50][25] comme exemple : 
    char ** Var; 
    int size = 50; 
    int nb   = 25; 
    int i = 0; 
    int j = 0; 
    Var = (char **)malloc(size * sizeof(char*)); //corrigé : char* et pas char
    while(i++ < size) 
    { 
         Var[i] = (char *)malloc(nb * sizeof(char)); 
    }

  7. #7
    duj
    duj est déconnecté
    Membre confirmé

    Profil pro
    Inscrit en
    Juillet 2003
    Messages
    141
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juillet 2003
    Messages : 141
    Points : 474
    Points
    474
    Par défaut
    A non, là je ne suis pas d'accord, ce qu'il a écrit est correct, je suis presque sûr qu'il ne faut pas allouer char par char.

    C'est justement partant de cette certitude, qu'il me semble logique que la method 2 de la FAQ soit correcte : puisque on peut tout allour pour une dimension, pourquoi par pour deux? Et comme en plus c'est ds la faq, raison de plus
    Parfois, Google fait des miracles

  8. #8
    Membre actif
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    258
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2003
    Messages : 258
    Points : 288
    Points
    288
    Par défaut
    Je n'ai (au cours des 3 ans de prog en C) jamais utilisé sizeof(char*) et ca a toujours marcher.

    Maintenant je me trompe peut-être :

    En tout cas je viens de regarder :

    sizeof(char) = 1;
    sizeof(char*) = 4;

    Sous win2k avec VC++ 6.0

  9. #9
    Membre du Club

    Inscrit en
    Mai 2003
    Messages
    39
    Détails du profil
    Informations forums :
    Inscription : Mai 2003
    Messages : 39
    Points : 67
    Points
    67
    Par défaut
    On reprend, ya plein de trucs faux.

    Première dimension :
    taille*sizeof(char*)

    Deuxième dimension :
    taille*taille2

    En tout :
    taille*sizeof(char*) + taille*taille2

    Ce qui donne :
    taille*(sizeof(char*) + taille2)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tab = malloc(taille*(sizeof(char*) + taille2));
    1ERE SOLUTION : la boucle for qui fait que :

    tab[0] doit pointer vers tab + taille ( "*sizeof(char*)" est implicite) + 0*taille2 (doit être casté)
    tab[1] doit pointer vers tab + taille ( "*sizeof(char*)" est implicite) + 1*taille2 (doit être casté)

    Il manque juste les cast pour faire fonctionner tout ça.

    2EME SOLUTION :
    Si on veut pas s'embêter avec ça c'est possible, mais il faut un pointeur de tableau qui référence la zone mémoire :

    EDIT : un tableau n'étant pas un objet, il est inutile d'allouer la première dimension :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    typedef char (*type_t)[taille2];
    char** tab = (char**)malloc(taille*taille2);
    type_t tab_ptr = (type_t)tab;
    Qui se simplifie en :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    typedef char (*type_t)[taille2];
    type_t tab_ptr = (type_t)malloc(taille*taille2);
    tab_ptr s'utilise ensuite comme si il avait été déclaré comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char tab_ptr[taille][taille2];

  10. #10
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par duj
    A non, là je ne suis pas d'accord, ce qu'il a écrit est correct, je suis presque sûr qu'il ne faut pas allouer char par char.

    C'est justement partant de cette certitude, qu'il me semble logique que la method 2 de la FAQ soit correcte : puisque on peut tout allour pour une dimension, pourquoi par pour deux? Et comme en plus c'est ds la faq, raison de plus
    Oui la methode 2 de la FAQ est correct (la 1 aussi d'ailleurs et peut etre plus simple a comprendre). Par contre effectivement comme le fait remarquer leneuf22 si tu veux acceder a un ellement de tableau par la syntaxe tab[i][j], il faut creer un tableau de pointeur tab et affecter les adresses de ce tableau avec les adresse des elements du premier tableau. Par contre tu peux te passer de cette affectation en accedant aux elements par tab[i*size+j].

    Yabo >> quand tu alloue ta premiere dimension du tableau, en faut tu cree un tableau de size pointeur sur char* (puisque qu'ensuite tu alloue un tableau de char dans cette adresse), donc c'est bien sizeof(char*) et non sizeof(char) qu'il faut utiliser.

  11. #11
    Membre du Club

    Inscrit en
    Mai 2003
    Messages
    39
    Détails du profil
    Informations forums :
    Inscription : Mai 2003
    Messages : 39
    Points : 67
    Points
    67
    Par défaut
    Citation Envoyé par gl
    Citation Envoyé par duj
    A non, là je ne suis pas d'accord, ce qu'il a écrit est correct, je suis presque sûr qu'il ne faut pas allouer char par char.

    C'est justement partant de cette certitude, qu'il me semble logique que la method 2 de la FAQ soit correcte : puisque on peut tout allour pour une dimension, pourquoi par pour deux? Et comme en plus c'est ds la faq, raison de plus
    Oui la methode 2 de la FAQ est correct (la 1 aussi d'ailleurs et peut etre plus simple a comprendre). Par contre effectivement comme le fait remarquer leneuf22 si tu veux acceder a un ellement de tableau par la syntaxe tab[i][j], il faut creer un tableau de pointeur tab et affecter les adresses de ce tableau avec les adresse des elements du premier tableau.
    La solution du pointeur de tableau que j'ai expliquée plus haut est beaucoup plus efficace et moins gourmande, car il n'y a aucune affectation à faire, et l'on peut accéder aux éléments par tab[i][j]

    Un exemple entier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <stdio.h>
    #include <stdlib.h>
     
    int main(void) {
    	int taille, taille2;
    	scanf("%d", &taille);
    	scanf("%d", &taille2);
    	char (*montab)[taille2] = malloc(taille*taille2*sizeof(char));
    	montab[2][5] = 12; //entrez une valeur correcte pour les scanf :)
    	return 0;
    }
    Citation Envoyé par gl
    , il faut creer un tableau de pointeur tab et affecter les adresses de ce tableau avec les adresse des elements du premier tableau. Par contre tu peux te passer de cette affectation en accedant aux elements par tab[i*size+j].
    Ha, je n'avais pas compris qu'il y accédait comme ça, d'où mon désaccord sur les autres posts... désolé !

  12. #12
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par leneuf22
    La solution du pointeur de tableau que j'ai expliquée plus haut est beaucoup plus efficace et moins gourmande, car il n'y a aucune affectation à faire, et l'on peut accéder aux éléments par tab[i][j]

    Un exemple entier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <stdio.h>
    #include <stdlib.h>
     
    int main(void) {
    	int taille, taille2;
    	scanf("%d", &taille);
    	scanf("%d", &taille2);
    	char (*montab)[taille2] = malloc(taille*taille2*sizeof(char));
    	montab[2][5] = 12; //entrez une valeur correcte pour les scanf :)
    	return 0;
    }
    J'ai un petit doute sur ton exemple, et VC++ est incapable de la compiler.

    Et utiliser les typedef comme tu l'expliquait auparavant, impose que taille2 soit une constante si je ne me trompe pas.

  13. #13
    Membre du Club

    Inscrit en
    Mai 2003
    Messages
    39
    Détails du profil
    Informations forums :
    Inscription : Mai 2003
    Messages : 39
    Points : 67
    Points
    67
    Par défaut
    VC++ n'est pas un compilateur C à jour.
    Ce code est du C de la dernière norme (C99) -> GCC le compile sans problèmes !

    La norme C99 autorise les tableaux à taille inconnue à la compilation, donc le typedef est valide.

  14. #14
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par leneuf22
    VC++ n'est pas un compilateur C à jour.
    Ce code est du C de la dernière norme (C99) -> GCC le compile sans problèmes !

    La norme C99 autorise les tableaux à taille inconnue à la compilation, donc le typedef est valide.
    J'avoue que j'ignorais que les tableaux a taille inconnue etait egalement accepte dans les typedef, donc ca devrait marcher effectivement sur des compilateurs C99.

    Quant a utiliser les raffinements de la derniere norme, c'est sympa, mais il y a pas enormement de compilateurs qui accepte de les compiler (VC++ n'est pas le seul a ne pas accepter les tailles inconnues et autres "nouveautes" du meme style). Autant essayer d'utiliser des methodes plus traditionnelles qui fonctionnent tout aussi bien.

  15. #15
    Membre du Club

    Inscrit en
    Mai 2003
    Messages
    39
    Détails du profil
    Informations forums :
    Inscription : Mai 2003
    Messages : 39
    Points : 67
    Points
    67
    Par défaut
    Citation Envoyé par gl
    Quant a utiliser les raffinements de la derniere norme, c'est sympa, mais il y a pas enormement de compilateurs qui accepte de les compiler (VC++ n'est pas le seul a ne pas accepter les tailles inconnues et autres "nouveautes" du meme style). Autant essayer d'utiliser des methodes plus traditionnelles qui fonctionnent tout aussi bien.
    Ou utiliser GCC qui est quand même extrêmement répandu
    GCC n'accepte pas encore toutes les nouveautés du C99... mais ça viendra.

    La sortie d'un ouvrage de référence sur le C99 devrait accélérer tout ça :
    http://www.amazon.fr/exec/obidos/ASIN/013089592X/171-6452989-2757855

  16. #16
    HRS
    HRS est déconnecté
    Membre confirmé
    Avatar de HRS
    Inscrit en
    Mars 2002
    Messages
    677
    Détails du profil
    Informations forums :
    Inscription : Mars 2002
    Messages : 677
    Points : 638
    Points
    638
    Par défaut
    le Mingw-2.0.0 (gcc 3.2 pour windows) compile correctement le code
    suivant mais pas le bcc5.5 (erreur tab.c 8:cannot convert 'void *' to 'char(*)[1]'

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    #include <stdio.h> 
    #include <stdlib.h> 
     
    int main(void) { 
       int taille, taille2; 
       scanf("%d", &taille); 
       scanf("%d", &taille2); 
       char (*montab)[taille2] = malloc(taille*taille2*sizeof(char)); 
       montab[2][5] = 12; //entrez une valeur correcte pour les scanf :) 
       return 0; 
    }
    curieusement avec le même Mingw 2.0.0, si au lieu de

    gcc -otab tab.c

    je fais

    g++ -otab tab.cpp

    j'ai la même erreur qu'avec le bcc5.5

  17. #17
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par HRS
    curieusement avec le même Mingw 2.0.0, si au lieu de

    gcc -otab tab.c

    je fais

    g++ -otab tab.cpp

    j'ai la même erreur qu'avec le bcc5.5
    Etrange ! Se pourrait que ce soit une forme acceptee en C et pas/pas encore en C++, ce qui expliquerait que ca ne fonctionne pas sous VC++ ni sous BCC.

  18. #18
    Membre du Club

    Inscrit en
    Mai 2003
    Messages
    39
    Détails du profil
    Informations forums :
    Inscription : Mai 2003
    Messages : 39
    Points : 67
    Points
    67
    Par défaut
    La norme ISO du C++ date de 98, et donc le C99 n'est plus compatible avec le C++.
    (dans le bouquin sur le C99 cité en page précédente, la compatibilité C/C++ est abordée à chaque chapitre)

  19. #19
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par leneuf22
    La norme ISO du C++ date de 98, et donc le C99 n'est plus compatible avec le C++.
    (dans le bouquin sur le C99 cité en page précédente, la compatibilité C/C++ est abordée à chaque chapitre)
    La date de publication des normes, n'est pas forcement significative, en effet une norme met assez longtemps (et pas mal de draft) avant d'etre publiee. De plus certaines des evolutions sur les normes C etait justement d'accepter des syntaxes valides en C++ (par exemple le commentaire //).

  20. #20
    Membre du Club

    Inscrit en
    Mai 2003
    Messages
    39
    Détails du profil
    Informations forums :
    Inscription : Mai 2003
    Messages : 39
    Points : 67
    Points
    67
    Par défaut
    Ce que je sais c'est que le C99 n'a jamais eu pour vocation de rester compatible avec le C++ (ce qui est marrant quand on sait que C++ a fait des sacrifices pour rester compatible avec le C de l'époque...)

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. [XL-2007] Tableau, première dimension dynamique
    Par VieuxCamarade dans le forum Macros et VBA Excel
    Réponses: 7
    Dernier message: 28/10/2013, 22h33
  2. Réponses: 4
    Dernier message: 30/07/2013, 16h21
  3. Créer un tableau à deux dimensions dynamique
    Par dev14 dans le forum Langage
    Réponses: 2
    Dernier message: 07/02/2012, 09h12
  4. Problème tableau 2 dimensions dynamique
    Par Beaudelicius dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 22/08/2011, 14h24
  5. creation d'un tableau double dimension dynamiquement
    Par elmcherqui dans le forum C++
    Réponses: 3
    Dernier message: 09/07/2009, 20h05

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