TABLEAUX A PLUSIEURS DIMENSIONS:

Présenté par ASLAM Waheed, DEUG TI 2, juin 1998


Table des Matières

  1. Déclaration
  2. Initialisation
  3. Accès à un élément
  4. Lien entre tableau et pointeur
  5. Applications
    1. Initialisation d'un tableau à deux dimensions
    2. Fonction traitant un tableau à plusieurs dimensions
    3. Calcul matriciel
    4. Programme calculant le déterminant d'une matrice(N,N)

Les tableaux à plusieurs dimensions sont très utiles. Ils permettent en particulier de représenter des matrices.

Après un cours compact et complet, nous verrons, à travers les diverses applications, comment on peut manipuler les tableaux multidimensionnels.

Déclaration

Le langage C autorise les tableaux à plusieurs dimensions. En effet, l'opérateur[ ] peut être juxtaposé à un autre opérateur, pour définir des tableaux de tableaux.

char ecran[24][80] : ecran est un tableau composé de 24 lignes et de 80 colonnes. Ce tableau est complété par des caractères, d'où la syntaxe char.

int matrice[100][100] : matrice est un tableau formé de 100 tableaux constitués chacun de 100 entiers. Elle réserve une zone de 100*100=10000 entiers.

int matrices[10][10][10] : dans ce cas, il s'agit de 10 tableaux de tableaux de 10*10 d'entiers.

Il faut souligner qu'il n'y a aucune limite sur le nombre d'indices d'un tableau. La seule limite est celle de l'espace mémoire disponible.

On peut encore définir un tableau à plusieurs dimensions par un tableau de lignes. On peut l'expliciter par typedef :

typedef int ligne[3]
typedef ligne matrice[2];

est équivalent à: int matrice[3][2];

Initialisation

Le tableau à plusieurs dimensions peut être initialisé, soit lors de sa déclaration, soit au cours de la programmation.

int tab[2][5]={{0,1,2,3,4},{4,3,2,1,0}};

est aussi équivalent à : int tab[2][5]={0,1,2,3,4,4,3,2,1,0}

Mais, la première façon d'écrire met directement en évidence le rangement des valeurs initiales. Puisque la première ligne du tableau tab comprend les chiffres 0,1,2,3,4 et la seconde ligne par 4,3,2,1,0.

Il est important de bien comprendre et connaître le rangement en mémoire des différents éléments d'un tableau. (NdT au contraire, je trouve cela inutile voire malsain)

En langage C, les éléments du tableau sont rangés dans l'ordre obtenu en faisant varier d'abord le dernier indice. C'est-à-dire que le compilateur remplit les cases du tableau en commencant par les plus imbriquées.

Voici quelques applications :

/* Initialisation complète */
int mat [2][4]={1,2,3,4,5,6,7,8};

positionnement de la matrice :

1

2

3

4

5

6

7

8

/* Initialisation incomplète */
int mat [2][4]={{1},{2,3}};

positionnement de la matrice :

1

0

0

0

2

3

< ALIGN="CENTER">0

0

Accès à un élément

Chaque élément est repéré par sa position dans le tableau. Il faut donner autant d'indices qu'il y a de dimensions.

Il n'y a aucun contrôle des indices. Mais dans ce cas, il est possible de "rester" dans le tableau en changeant de colonne.

Voici un programme mettant en évidence le rangement des variables:

int i,matrice[3][2][2]={0,1,2,3,4,,5,6,7,8,9,10,11};
i=matrice [0][0][0];                    /* i=0*/
i=matrice [1][1][1];                    /* i=7*/
i=matrice [2][1][0];                    /* i=10*/
i=matrice [1][2][3];                    /* i=11=matrice[1*4+2*2+3]*/
i=matrice [0][3][4];                    /* i=10=matrice[0*4+3*2+4]*/
i=matrice [3][0][0];                    /* i=erreur car en dehors du tableau*/

Dans cet exemple, il ne faut pas oublier de compter la ligne 0, la colonne 0, le tableau 0. Dans le cas où l'on se trompe dans la valeur maximum de chaque indice, le langage C calcule la position dans le tableau à partir des indices, suivant leurs poids. Le premier est multiplié par la taille d'un tableau, le deuxième par la taille d'une ligne et le dernier est simplement ajouté.

De plus, tout dépassement des limites du tableau, s'il n'a pas trop de conséquences en lecture, peut être catastrophique en écriture.

Lien entre tableau et pointeur

Comme pour les tableaux à une dimension, le nom du tableau lui-même indique l'emplacement du premier élément. Ainsi, dans la déclaration int tab [3][2] , tab représente l'adresse du premier élément du tableau (&tab[0][0]).

Comme un tableau à plusieurs dimensions est un tableau de tableaux, il est possible de désigner un sous-tableau. Ainsi, tab[0] représente l'adresse du premier sous-tableau (&tab[0][0]) et tab[1] représente l'adresse du deuxième sous-tableau (&tab[1][0]).

Voici un exemple pour illustrer cette partie du cours :

void main(void)
{
int i,*ptrmat1,*ptrmat2,mat[3][2][2]={0,1,2,3,4,5,6,7,8,9,10,11};
ptrmat1=(int*)mat;
i=*(ptrmat1+10);            /* une seule dimension via le pointeur: i=10 */
ptrmat2=(int*)mat[1];       /* pointe le sous-tableau {{4,5},{6,7}} */
i=*ptrmat2;                 /* i=4 premier élément du  sous-tableau */
i=*(ptrmat2+3);             /* i=7 dernier élément du sous-tableau */

ptrmat2=(int*)mat[0][1];    /* pointe le 1er élément de la ligne1*/
i=*ptrmat2;                 /* i=2*/
ptrmat1=(int*) mat[0][0];   /* pointe le 1er élément du sous-tableau 0*/
i=*ptrmat1;                 /* i=0*/
i=ptrmat2- ptrmat1          /* i=2*/
}

Applications

Initialisation d'un tableau à deux dimensions

Ce programme permet d'initialiser tous les éléments du tableau de deux lignes et deux colonnes à zéro.

{
int mat[2][2],i,j;
     for (i=0;i<2;i++)
           for (j=0;j<2;j++)
                         mat[i][j]=0;
}

On constate que ce programme est très utile, si l'on possède une matrice avec un grand nombre de colonnes et de lignes.

Fonction traitant un tableau à plusieurs dimensions

Dans cet exemple, il s'agit d'échanger le numéro de ligne avec le numéro de la colonne. En plus clair, les lignes deviennent les colonnes et inversement .

void Transpose (int tab1[2][5], int tab2[5][2])
{
int i,j;
for (j=0;j<2;j++)
 for (i=0;i<5;i++)
  tab2[i][j]=tab1[j][i];
}

void main(void)
{
int matrice [2][5]={{0,1,2,3,4},{5,6,7,8,9}},transpmat[5][2];
Transpose ( matrice, transpmat);
}

Nous pouvons aussi utiliser les pointeurs pour ce genre d'application:

void Transpose (int *ptrtab1, int*ptrtab2 )
{
int i,l;c;

for (i=0;i<l*c;i++,ptrtab1++)
    if (i<l)
           *(ptrtab2+c*i)=ptrtab1;
    else *(ptrtab2+c*(i-l)+1=*ptrtab1;
}

void main(void)
{
int matrice [2][5]={{0,1,2,3,4},{5,6,7,8,9}},transpmat[5][2];
Transpose ( (int*)matrice, (int*)transpmat);
}

à l'affichage on obtient:

                01234               05
                56789               16
                                    27
                                    38
                                    49

Calcul matriciel

Soient la matrice (M lignes, L colonnes) et la matrice(L lignes, N colonnes), la multiplication de ces deux matrices a pour matrice (M lignes, N colonnes).

# define max 10
typedef float ligne[max];
typedef ligne matrice[max];


void main (void)
{
matrice m1,m2,m3;
int l1,l2,l3,c1,c2,c3,l,c,i;
float somme;
for (l=0;l<l3;l++)
      for (c=0;c<c3;l++)
            {
                somme=0;
                for (i=0,i<l2;i++)
                somme+=m1[l][i]*m2[i][c];
                m3[l][c]=somme;
             }
}

N.B. Pour comprendre ce programme, il est conseillé de se munir d'un brouillon. En se créant des matrices fictives et en multipliant les matrices, on peut trouver l'algorithme.

Programme calculant le déterminant d'une matrice(N,N)

Voici un programme en plusieurs blocs permettant de calculer le déterminant d'une matrice(N,N). (NdT il existe d'autres méthodes plus efficaces)

bloc 1 :

#include <stdio.h>
#include<stdlib.h>
#define DIM 10

typedef float ligne[DIM];
typedef lignematrice[DIM];
long nbappel;

Ce bloc permet de déclarer les différentes variables qui seront utilisées dans le programme.

bloc 2 :

void lecture (matrice t, int *lig)
{
     int l,c;
     float f;
     puts(''Dimension de la matrice ?'');
     scanf(''%d'',lig);
          for (l=0;l<*lig;l++)
                for (c=0;c<*lig;c++)
                     {
                      printf (''élément [%d,%d]?'',l,c);
                      scanf(''%f'',&f);
                      t[l][c]=f;
                     }
}

Comme son nom l'indique, il s'agit de lire les données servant à compléter les matrices.

Deux boucles imbriquées l'une dans l'autre suffisent pour lire les différentes cases du tableau à deux dimensions.

bloc 3 :

void copiesauflc (matrice source,matrice dest, int dim, int ligavirer)
{
    int l,c,ld=0;
         for (l=0;l<dim;l++)
               if(l!=ligavirer)
                  {
                    for(c=1;c<dim;c++)
                    dest[ld][c-1]=source[1][c];
                    ld++;
                   }
}

Cette fonction permet de supprimer la ligne et la colonne qui ne sert pas pour le calcul du déterminant.

bloc 4 :

float determinant (matrice m, int dim)
{
           matrice sous_m;
           int l,signe=1;
           float det=0;
                nbappel++;
                if (dim==1) return (m[0][0]);
                       for (l=0;l<dim;l++)
                             {
                               copiesauflc(m,sous_m,dim,1)
                               det+=signe*m[1][0]*determinant(sous_m,dim-1);
                                signe=-signe;
                              }
           return(det);
}

Dans cette fonction, il apparaît une récurrence permettant de calculer les différents déterminants formés par la matrice principale.

bloc 5 :

void main (void)
{
int taille;
matrice mat;
 
        lecture (mat,taille);
        printf("determinant:%20.17f",determinant(mat,taille));
        printf("en %d appels \n",nbappel);
}

Le programme principal est simple, car il s'agit seulement de déclarer les différentes fonctions utiles au calcul du déterminant.


retour retour au sommaire

Free Web Hosting