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 :

tableau à plusieurs dimensions


Sujet :

C

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    247
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 247
    Par défaut tableau à plusieurs dimensions
    bonjour,

    Je souhaite céer un jeu sur un damier 8*8
    j'ai créer une fonction qui affiche ce damier : affiche

    dans mon main pour l'instant j'ai juste initialisé le damier

    chaque case de mon damier contient un type, que j'ai défini, nommé caze

    quelle doit etre alors la féfinition de ma fonction affich ?
    j'ai essayé ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void affich(caze othello[][]);
    en faisant lanalogie avec un tableau à une dimension.

    pourtant ce code n'est pas compilable (avec gcc)
    j'ai alors testé ceci à tout hasard
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void affich(caze othello[][8]);
    et ceci marche très bien.
    quelle est la raison ?


    autre chose, pour contourner le pb de passage par référence en C, il faut souvent passer en paramètre l'adresse d'un objet dans les différentes fonctions sauf pour les tableaux qui sont considérés eux mêmes comme des pointeurs. Déjà ai-je bien raison ? Et si oui en est-il de même pour les tableaux à n dimensions ?


    Merci vraiment bcp pour votre lecture. Les réponses sont les bienvenues...

  2. #2
    Rédacteur

    Avatar de gege2061
    Femme Profil pro
    Administrateur de base de données
    Inscrit en
    Juin 2004
    Messages
    5 840
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Juin 2004
    Messages : 5 840
    Par défaut Re: tableau à plusieurs dimensions
    Bonjour,
    Citation Envoyé par pekka77
    j'ai essayé ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void affich(caze othello[][]);
    en faisant lanalogie avec un tableau à une dimension.

    pourtant ce code n'est pas compilable (avec gcc)
    j'ai alors testé ceci à tout hasard
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void affich(caze othello[][8]);
    et ceci marche très bien.
    quelle est la raison ?
    Normal, il faut spécifier la deuxième dimension, ce qui ai le cas dans la seconde fonction

    Citation Envoyé par pekka77
    les tableaux qui sont considérés eux mêmes comme des pointeurs. Déjà ai-je bien raison ? Et si oui en est-il de même pour les tableaux à n dimensions ?
    c'est l'inverse, un pointeur peut être utiliser comme un tableau (avec l'allocation dynamique):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int *tab = malloc( sizeof( *tab ) * SIZE );
    /* Dans ce cas : */
    *(tab + i) = tab[i]
    mais l'inverse n'est pas vrai.

    En espérant avoir répondue à tes questions.

    [edit]Je vous ai tous eu [/edit]

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

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut Re: tableau à plusieurs dimensions
    Citation Envoyé par pekka77
    Je souhaite céer un jeu sur un damier 8*8
    j'ai créer une fonction qui affiche ce damier : affiche
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void affich(caze othello[][]);
    en faisant lanalogie avec un tableau à une dimension.

    pourtant ce code n'est pas compilable (avec gcc)
    Normal.
    j'ai alors testé ceci à tout hasard
    Il faut arréter de programmer au hasard, et apprendre le C sérieusement. Il y a des références de livres et des tutoriels sur ce site...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void affich(caze othello[][8]);
    et ceci marche très bien.
    quelle est la raison ?
    Le compilateur n'est pas devin. Il a besoin de la taille pour faire ses calculs d'adresse. Pas de taille, pas de calculs... Pour la dimension de gauche, le type suffit, c'est pourquoi on peut ommettre la taille (comme dans un tableau à une dimension).
    autre chose, pour contourner le pb de passage par référence en C, il faut
    Tous les passages de paramètres se font par valeur en C.
    souvent passer en paramètre l'adresse d'un objet dans les différentes fonctions sauf pour les tableaux qui sont considérés eux mêmes comme des pointeurs. Déjà ai-je bien raison ? Et si oui en est-il de même pour les tableaux à n dimensions ?
    Dans la littérature anglo-saxone sur le C, on trouve des phrases du genre :
    An array decays to a pointer when passed to a function"
    Ca signifie en gros, que pour passer un tableau à une fonction, on passe son adresse via un paramètre pointeur. Ca ne signifie nullement qu'un tableau est un pointeur.

  4. #4
    Membre émérite
    Avatar de Pouic
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    669
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 669
    Par défaut Re: tableau à plusieurs dimensions
    Citation Envoyé par pekka77
    pourtant ce code n'est pas compilable (avec gcc)
    j'ai alors testé ceci à tout hasard
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void affich(caze othello[][8]);
    et ceci marche très bien.
    quelle est la raison ?
    Parceque en C, lorsqu'on passe un tableau à deux dimensions, il faut preciser le nombre de colonnes à la declaration. Le nombre de lignes n'est pas utile dans le sens ou ce que tu passes à la fonction est un pointeur sur un tableau ed lignes (contenant chacunes 8 elements)
    Donc les declarations suivantes sont equivalentes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    void affich(caze othello[][8]);
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    void affich(caze othello[8][8]);
    autre chose, pour contourner le pb de passage par référence en C, il faut souvent passer en paramètre l'adresse d'un objet dans les différentes fonctions sauf pour les tableaux qui sont considérés eux mêmes comme des pointeurs. Déjà ai-je bien raison ? Et si oui en est-il de même pour les tableaux à n dimensions ?
    Non. En C, le passage des arguments se fait par valeur : c'est pour contourner cela et pouvoir modifier des elements exterieurs aux fonctions qu'on passe une adresse sur l'element en question.
    C'est vrai pour tout argument que l'on voudrait modifier (suaf les expressions constantes)

    <edit>
    Arf, devancé par Emmanuel...
    </edit>

    ++
    Pouic
    Software becomes slower faster than hardware becomes faster
    [size=1]
    http://xrenault.developpez.com

  5. #5
    Membre confirmé
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2004
    Messages
    84
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2004
    Messages : 84
    Par défaut
    Salut...

    A l'IUT informatique on apprend a définir des types tableau et tout devient plus simple :

    const int NB_CASES = 8 ;

    typedef caze Damier [NB_CASES][NB_CASES] ; // ton nouveau type

    Damier damier ; // ton damier de type Damier


    Pour ta fonction afficher tu as juste a passer ton damier en entrée, tu écris donc :

    void afficher (const Damier d) ; // passage par valeur


    Dans le cas ou tu dois modifier ton damier tu le passe en mode qu'on appelle chez nous "mise à jour", ton en-tete devient donc :

    void taFonction (Damier d) ; // passage par adresse


    Voila, prévenez-moi si j'ai dit des betises...

    En tout cas je t'engage vivement à déclarer un nouveau type pour tes tableaux c'est très pratique !

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

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par Tijee
    Salut...

    A l'IUT informatique on apprend a définir des types tableau et tout devient plus simple :

    const int NB_CASES = 8 ;

    typedef caze Damier [NB_CASES][NB_CASES] ; // ton nouveau type

    Damier damier ; // ton damier de type Damier


    Pour ta fonction afficher tu as juste a passer ton damier en entrée, tu écris donc :

    void afficher (const Damier d) ; // passage par valeur


    Dans le cas ou tu dois modifier ton damier tu le passe en mode qu'on appelle chez nous "mise à jour", ton en-tete devient donc :

    void taFonction (Damier d) ; // passage par adresse


    Voila, prévenez-moi si j'ai dit des betises...

    En tout cas je t'engage vivement à déclarer un nouveau type pour tes tableaux c'est très pratique !
    C'est trompeur, car on ne peut pas récupérer la taille avec un type tableau. Il vaut mieux un type 'pointeur sur tableau'
    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
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
     
    #include <stdio.h>
    #include <stdlib.h>
     
    typedef struct
    {
       int a;
       int b;
    }
    caze;
     
    typedef caze (*pDamier)[8][8];
     
    void clean (pDamier d)
    {
       size_t i;
     
       for (i = 0; i < sizeof *d / sizeof **d; i++)
       {
          size_t j;
     
          for (j = 0; j < sizeof **d / sizeof ***d; j++)
          {
             (*d)[i][j].a = 'A' + i + j;
             (*d)[i][j].b = 'a' + i + j;
          }
       }
    }
     
    void display (pDamier d)
    {
       size_t i;
     
       for (i = 0; i < sizeof *d / sizeof **d; i++)
       {
          size_t j;
     
          for (j = 0; j < sizeof **d / sizeof ***d; j++)
          {
             printf ("%c%c ", (*d)[i][j].a, (*d)[i][j].b);
          }
          printf ("\n");
       }
       printf ("\n");
    }
     
    int main (void)
    {
       pDamier d = malloc (sizeof *d);
       {
          if (d != NULL)
          {
             clean (d);
             display (d);
             free (d), d = NULL;
          }
       }
     
       system ("pause");
       return 0;
    }

  7. #7
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    247
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 247
    Par défaut
    Merci à tous pour vos réponses !
    quand je parlais du pb de passage par référence, je voulais justement dire que le langage c ne permet pas un tel passage et que celui ci se fait par valeur. J'ai du mal me faire comprendre, excusez moi.

    Les tutos je les ai lus plusieurs fois et je pense les avoir compris mais il m'est utile d'éclaircir certains points, la notion de pointeur par exemple n'est pas forcément évidente au premier abord. Répondre à mes questions me permets vraiment de progresser, bien plus qu'en relisant un tuto.

    Pour ceux à qui cela ne dérange pas, pouvez vous me réexpliquer pourquoi il n'est pas utile de préciser le nombre d'éléments de la première dimension d'un tableau lorsqu'on passe celui-ci en paramètre dans une fonction.

    Merci

  8. #8
    Membre Expert

    Inscrit en
    Mai 2002
    Messages
    720
    Détails du profil
    Informations forums :
    Inscription : Mai 2002
    Messages : 720
    Par défaut
    Je suis pas expert en C mais j'ai de vagues souvenirs qui me font penser que ....

    Imagine une info qui tient sur un octet (un caractere par exemple)...

    Si tu met du texte dedant, que ton tableau est a une l'adresse ``x'', tu peux afficher la lettre ``n'' en lisant le contenu de ``mot[n]''. Toutes les donnes etant a la suite les unes des autres dans la representation d'un que se fait un homme (une serie de lettre qui se suivent) et dans la memoire.

    Maintenant, si tu prends un tableau, il y a un probleme : nous, on imagine un tableau a deux dimensions comme un assemblages de lignes et de colones, mais la memoire de l'ordinateur n'est qu'une suite d'information.... La solution est simple : si tu doit stocker 10 mots de 10 caracteres, tu transforme ton tableau de taille 10x10 en une ligne de 100 caractere et tu sais qu'il faut couper tous les 10. C'est comme ca que ca fonctionne avec la memoire. Si tu veux aller a la lettre ``n'' du mot ``m'' il faut se deplacer par rapport au debut de la chaine de 100 caracteres de ``10*m+n'', car chaque mot fait 10 caracteres.... ce 10 par lequel tu as multiplie, il est necessaire pour manipuler ton tableau. Car comment faire la difference entre un tableau de 10x10, un de 100x1 un de 1x100, un de 2x50, .... qui ne sont somme toutes que des series de 100 elements consecutifs ? Donc pour un tableau a deux dimensions, il faut preciser la longueur des lignes... Le nombre de ligne n'est pas a preciser car il n'est pas necessaire pour faire des calculs (Si on se plante, ca fegfault et puis c'est regle ).

    Wala, j'espere pas avoir dit trop d'enormites ....

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

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par pekka77
    <...>pouvez vous me réexpliquer pourquoi il n'est pas utile de préciser le nombre d'éléments de la première dimension d'un tableau lorsqu'on passe celui-ci en paramètre dans une fonction.
    Dans le contexte d'un paramètre (j'insiste), les syntaxes

    T *p , T p[123] et T p[]

    sont équivallente. On passe l'adresse d'un tableau, la dimension n'est pas utilisée. Dans la fonction, on récupère l'adresse du tableau. Comme on a le type, et grâce à l'arithmétique des pointeurs, on a ce qu'il faut pour calculer l'adresse de chaque élement du tableau. Dans tous ces cas, Le nombre d'éléments manque, et il est souhaitable de le passer en paramètre si on en a besoin:
    Dans le cas d'un tableau à 2 dimensions, on peut écrire

    T (*p)[123] , T p[456][123] et T p[][123]

    Si on ne mettait pas la dimension de droite (toutes les dimensions de droite), on ne pourrait pas calculer l'adresse de l'élément.

  10. #10
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    247
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 247
    Par défaut
    Donc en gros, il y a deux façon de déclarer un tableau :

    - de manière dite "statique" :
    - de manière dite "dynamique" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    T=(int*)malloc(10*sizeof(int));
    Dans les deux cas on peut faire passer le tableau en paramètre d'une fonction de 3 façons différentes (celles que tu as dites)

    Mais si on crée un tableau de 10 entiers de la meme manière que j'ai montré ci dessus, à quoi ça sert de faire passer le nombre d'éléments du tableau ?
    Par exemple si je veux l'initialiser, j'aurai juste à faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void initialiser(int T[]) /* ou void initialiser(int T[10]) ou void initialiser(int *T)  /*
    {
    int i;
    for(i=0;i<10;i++) T[i]=0;
    }
    Il est vrai par contre que j'ai intérêt à entre la valeur 10 dans une constante et la faire paramètrer dans toutes les fonctions utilisant la taille du tableau, au cas où j'ai besoin de modifier la taille du tableau par la suite (pas dans le corps du programme bien sûr puisque j'ai réservé 10 cases pour le tableau). C'est ce que tu voulais dire ?

    Merci pour ces petites précisions.

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

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par pekka77
    Donc en gros, il y a deux façon de déclarer un tableau :

    - de manière dite "statique" :
    Hum... définir...
    - de manière dite "dynamique" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    T=(int*)malloc(10*sizeof(int));
    ou tout simplement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int *T = malloc(10 * sizeof *T);
    Dans les deux cas on peut faire passer le tableau en paramètre d'une fonction de 3 façons différentes (celles que tu as dites)

    Mais si on crée un tableau de 10 entiers de la meme manière que j'ai montré ci dessus, à quoi ça sert de faire passer le nombre d'éléments du tableau ?
    Parce qu'on peut en avoir besoin, ou qu'on a envie d'écrire du code souple qu'on ne va pas modifier parce qu'une taille change......
    Par exemple si je veux l'initialiser, j'aurai juste à faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void initialiser(int T[]) /* ou void initialiser(int T[10]) ou void initialiser(int *T)  /*
    {
    int i;
    for(i=0;i<10;i++) T[i]=0;
    }
    Et si maintenant, il fait une taille de 12, tu fais comment ? Ou si la taille n'est pas connue à la compilation ? Une fonction c'est pas fait pour regrouper des lignes de codes. C'est fait pour effectuer une opération precise définie par des interfaces et des comportements.

    Il est vrai par contre que j'ai intérêt à entre la valeur 10 dans une constante et la faire paramètrer dans toutes les fonctions utilisant la taille du tableau, au cas où j'ai besoin de modifier la taille du tableau par la suite (pas dans le corps du programme bien sûr puisque j'ai réservé 10 cases pour le tableau). C'est ce que tu voulais dire ?
    Pas vraiment. La même fonction peut servir à initialiser des tableaux de tailles différentes, voire de types différents avec une interface un peu plus complexe. C'est le principe des fonctions réultilisables (bibliothèques). Ne faire qu'une chose, mais le faire bien et de façon la plus générique possible...
    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
     
    void initialiser(int *T, size_t n)
    {
       size_t i;
       for (i = 0; i < n; i++) 
       {
          T[i]=0;
       }
    }
     
    int main (void)
    {
       int a[123];
       int b[456];
     
       initialiser (a, sizeof a / sizeof *a);
       initialiser (b, sizeof b / sizeof *b);
     
       return 0;
    }
    Pour calculer le nombre d'élements d'un tableau, je recommande la macro:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    #define NELEM(a) (sizeof(a) / sizeof *(a))
     
    ...
     
       initialiser (a, NELEM(a));
       initialiser (b, NELEM(b));
    évidemment, ça ne fonctionne qu'avec les tableaux (j'insiste...)

  12. #12
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    247
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 247
    Par défaut
    Ok je te remercie bcp ! ça m'éclaircit un peu les idées.

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 08/05/2007, 20h10
  2. Initialisation d'un tableau à plusieurs dimensions
    Par kinouseb dans le forum Windows Forms
    Réponses: 2
    Dernier message: 07/02/2007, 13h16
  3. problème avec un tableau à plusieurs dimensions
    Par lelutin dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 07/09/2006, 12h05
  4. Réponses: 3
    Dernier message: 26/05/2006, 19h49
  5. Réponses: 7
    Dernier message: 19/01/2006, 18h57

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