1. #1
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2013
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : mars 2013
    Messages : 38
    Points : 20
    Points
    20

    Par défaut Tableau dynamique 2 dimensions (norme C99)

    Bonjour,


    Je cherche a créer un tableau dynamique à dimensions.

    Jusqu'a present j'utilisais la methode :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int **tab = malloc(sizeof(*tab) * 20);
     
    for (i = 0; i < 20; i++)
        tab[i] = malloc(sizeof(**tab) * 50);
    Mais mon prof me disait qu'il y avait une autre méthode.. comme un gros imbécile j'ai laissé le fichier sur l'ordi de l'ecole et je ne peux pas le recup..
    brefs.. me voila a la recherche de l'autre methode sur le net, et je tombe sur ceci :

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

    avec un exemple plus bas :

    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;
    }
    Le souci c'est que quand je veux compiler ca, Visual Studio 2017 me dit que
    taille2 doit avoir une valeur de constante
    Le code fonctionne bien quand je remplace taille2 par une constante.

    Il est justement dis un peu plus bas dans le sujet de la source que c'est une erreur dans la norme en cours (le sujet date de 2003), mais que cela est accepté dans la (nouvelle) norme C99.
    On est en 2017, j'utilise donc visual studio 2017, et apparemment cela n'est tjrs pas accepter??!
    Comment puis je contourner ca?? Est ce que c'est possible de le contourner en utilisant cette méthode????
    Je précise que je compile en C et pas en C++ et mon extension de fichier est .c et pas .cpp (via les options de vs2017)

  2. #2
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    5 897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2006
    Messages : 5 897
    Points : 16 277
    Points
    16 277
    Billets dans le blog
    1

    Par défaut

    Bonjour

    Je ne peux pas te répondre à propos de VS2017 (pourquoi il accepte pas ta syntaxe etc). Probablement une option de compilation.

    A l'origine, le principe d'allocation dynamique d'un tableau 2D est exactement ce que tu as écrit au départ. Pour allouer un tableau n*m items on commence par allouer "n" pointeurs puis, pour chaque pointeur, on alloue "m" items.
    Toutefois, il y a une seconde méthode: utiliser un tableau 1D et lui allouer immédiatement "n*m" items puis utiliser des formules de transformation pour remplacer tab[x][y] de ton algo par tab[z] de ton code. C'est pas vraiment compliqué: z=x*m+y.
    Cette seconde méthode se base sur le fait que quoi qu'il arrive, un tableau même en "d" dimensions n'est au final qu'une longue suite d'octets en mémoire.

    Ensuite, le C a évolué. A l'origine, quand on créait des tableaux statiques, on ne pouvait créer que des tableaux de taille constante. Ainsi char tab[10] était autorisé mais int n=10; char tab[n] ne l'était pas. Puis il a évolué (C99) et le compilo a autorisé la création de tableaux de ce type.
    Et c'est cette méthode qui est utilisée dans l'exemple que tu cites. Tu remplis une variable "taille2" puis tu définis un tableau char *tab[taille2] qui contient donc "taille2" pointeurs. Mais chez-toi ça n'est pas autorisé et c'est pour ça que ça ne fonctionne que quand "taille2" est une constante.

    La seule chose qui me choque c'est que tu affectes à ce tableau le retour du malloc et ça j'ai jamais vu cette syntaxe. A priori je serais parti pour dire que la zone allouée est en quelque sorte "mappée" dans le tableau de pointeurs et donc que tab[0] contient le premier bloc de "taille" octets, tab[1] le bloc suivant etc. Mais outre que je peux pas dire si cette syntaxe est autorisée ou pas, ce n'est pas ce qui s'est passé chez-moi.

    Voici mon code
    Code c : 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
    #include <stdio.h>
    #include <stdlib.h>
     
    int main(void) {
    	int taille, taille2;
    	scanf("%d", &taille);
    	scanf("%d", &taille2);
    	char (*montab)[taille2] = malloc(taille2*taille*sizeof(char));
     
    	int i;
    	printf("montab=%lu\n", montab);
    	for (i=0; i < taille2; i++)
    		printf("montab[%d]=%lu\n", i, montab[i]);
     
    	return 0;
    }

    Et voici ce que ça donne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    moi@virtualux:/tmp$ make essai
    cc     essai.c   -o essai
    moi@virtualux:/tmp$ ./essai 
    5
    2
    montab=27922448
    montab[0]=27922448
    montab[1]=27922450
    Or si la zone allouée était correctement mappée dans le tableau, alors avec des blocs de "5" octets, les adresses auraient dû se suivre de 5 en 5 et non de 2 en 2. Ou alors j'ai raté un truc.

    Peut-être nous indiquer où tu as trouvé cet exemple nous aiderait à y voir plus clair. Surtout que cet exemple ne me parait pas bien fameux car on ne masque jamais un pointeur derrière un type (et à fortiori là il va jusqu'à masquer un tableau !!!)
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

  3. #3
    Membre chevronné
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    avril 2016
    Messages
    462
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : avril 2016
    Messages : 462
    Points : 2 040
    Points
    2 040

    Par défaut

    Citation Envoyé par Dunkhan Voir le message
    Il est justement dis un peu plus bas dans le sujet de la source que c'est une erreur dans la norme en cours (le sujet date de 2003), mais que cela est accepté dans la (nouvelle) norme C99.
    On est en 2017, j'utilise donc visual studio 2017, et apparemment cela n'est tjrs pas accepter??!
    La fonctionnalité en question s'appelle VLA (Variable Length Array). Comme elle est controversée, le support des VLA a été rendu optionnel en C11. Si les VLA ne sont pas supportés, le compilateur doit définir la macro __STDC_NO_VLA__ avec la valeur 1.
    Visual Studio 2015 ne supporte pas les VLA, donc il est probable que la version de 2017 ne les supporte pas non plus.

    Citation Envoyé par Sve@r Voir le message
    Or si la zone allouée était correctement mappée dans le tableau, alors avec des blocs de "5" octets, les adresses auraient dû se suivre de 5 en 5 et non de 2 en 2.
    C'est normal que les adresses se suivent de 2 en 2. montab étant déclaré char (*montab)[taille2], c'est un pointeur vers un tableau de taille taille2 qui, dans ton exemple, vaut 2. Donc, si on incrémente ce pointeur, il va passer au tableau de taille 2 suivant.

  4. #4
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    5 897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2006
    Messages : 5 897
    Points : 16 277
    Points
    16 277
    Billets dans le blog
    1

    Par défaut

    Citation Envoyé par Pyramidev Voir le message
    c'est un pointeur vers un tableau de taille taille2 qui, dans ton exemple, vaut 2.
    Exact. C'est en effet ce que j'avais raté. Ce n'est pas un tableau de "taille2" pointeurs mais un pointeur vers une suite de tableaux de taille "taille2" caractères. Et ce pointeur est ensuite mappé sur une zone de (chez-moi) 10 caractères; donc au final 5 tableaux de taille "2 caractères".

    Faut pas que je fasse boucler i sur "taille2" itérations mais sur "taille" itération pour voir tout le tableau.
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

  5. #5
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2013
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : mars 2013
    Messages : 38
    Points : 20
    Points
    20

    Par défaut

    Merci pour vos réponses

    Est ce que cela veut dire qu'il n'est possible de créer un tableau dynamique réellement dynamique??
    Je veux, dire, si je ne connais pas le nombre de tableau dont j'aurais besoin.. comment je fais alors??

  6. #6
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    mars 2015
    Messages
    245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : mars 2015
    Messages : 245
    Points : 379
    Points
    379

    Par défaut

    bonjour,tu peux utiliser un autre compilateur par exemple mingw-w64 dont le compilateur C, gcc.exe doit supporter les VLA

  7. #7
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    5 897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2006
    Messages : 5 897
    Points : 16 277
    Points
    16 277
    Billets dans le blog
    1

    Par défaut

    Citation Envoyé par Dunkhan Voir le message
    Je veux, dire, si je ne connais pas le nombre de tableau dont j'aurais besoin.. comment je fais alors??
    Avec du realloc qui te permet d'agrandir ce qui a déjà été alloué.

    Et moi personnellement, comme le realloc est gourmand en temps, je fais des agrandissements par lots. C'est à dire que je gère une taille allouée et une taille utilisée. Et quand je dois rajouter un élément, mais que la taille utilisée a déjà atteint la taille allouée, alors j'agrandis la taille allouée de "X" puis je fais un realloc de cette taille allouée.

    Exemple

    Code c : 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
    typedef struct {
        char *zone;
        char *tmp;
        size_t nb_items;
        size_t sz_alloc;
    } t_alloc;
     
    // Initialisation
    t_alloc myTab;
    myTab.zone=NULL;
    myTab.nb_items=0;
    myTab.sz_alloc=0;
     
    // Remplissage
    while (... lecture_quelconque_d_un_caractere_a_stocker...)
    {
        // Si on n'a pas/plus de place
        if (myTab.nb_items == myTab.sz_alloc)
        {
            // Agrandissement
            myTab.sz_alloc+=X;
            myTab.tmp=realloc(mytab.zone, myTab.sz_alloc * sizeof(char))   // Si la zone à réallouer est à NULL, alors realloc se comporte comme malloc
     
           // Verification allocation échouée
           if (myTab.tmp == NULL)
           {
                // Gestion de l'erreur - Généralement on libère ce qui a été alloué et on sort
               free(myTab.zone);  // C'est pour ne pas perdre le pointeur "zone" que je passe par un pointeur intermédiaire "tmp"
               return -1;
           }
     
           // Allocation réussie - On récupère la zone allouée
           myTab.zone=myTab.tmp;
        }
     
        // Ici, quoi qu'il arrive, on a de la place pour stocker le caractère lu
        myTab.zone[myTab.nb_items]=caractere_a_stocker;
     
        // On a un item de plus
        myTab.nb_items++;
    }

    Avec cette façon de faire, tu ne peux pas échouer...
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

  8. #8
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2013
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : mars 2013
    Messages : 38
    Points : 20
    Points
    20

    Par défaut

    Merci pour vos réponses.

    Je prend note de la façon de créer et reallouer des tableaux de Sve@r


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

Discussions similaires

  1. Réponses: 14
    Dernier message: 29/03/2014, 10h36
  2. [HashSet] Tableau dynamique à 2 dimensions
    Par ppopov dans le forum java.util
    Réponses: 5
    Dernier message: 21/01/2007, 17h21
  3. Réponses: 4
    Dernier message: 19/12/2006, 21h06
  4. declaration d'un tableau dynamique 2 dimensions
    Par mike600river dans le forum C++Builder
    Réponses: 4
    Dernier message: 22/05/2006, 09h53
  5. Réponses: 1
    Dernier message: 09/03/2006, 18h25

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