web-dev-qa-db-fra.com

Comment utiliser des expressions de pointeur pour accéder aux éléments d'un tableau à deux dimensions en C?

Je sais que pour les tableaux unidimensionnels, x=a[i] équivaut à x=*(a+i), mais comment puis-je accéder aux éléments d'un tableau bidimensionnel à l'aide de pointeurs?

35
Tudor Ciotlos

Résumé: Si vous avez un tableau multidimensionnel défini comme int [][], alors x = y[a][b] est équivalent à x = *((int *)y + a * NUMBER_OF_COLUMNS + b);


Détails ennuyeux:

La distribution (int *) de y ci-dessus mérite une explication, car sa nécessité peut ne pas être intuitive au premier abord. Pour comprendre pourquoi il doit être là, tenez compte des points suivants:

  1. L'arithmétique de pointeur typé en C/C++ ajuste toujours la valeur du pointeur typé (qui est une adresse) à la taille des octets type in lors de l'ajout/de la soustraction/de l'incrémentation/de la décrémentation par scalaire.

  2. Le type fondamental type d'une déclaration de tableau multidimensionnel (et non le type d'élément; le type variable) est un type de tableau de dimension inférieure à la dimension finale.

Le dernier (n ° 2) de ces derniers a vraiment besoin d'un exemple pour se solidifier. Dans ce qui suit, les variables ar1 et ar2 sont des déclarations équivalentes.

int ar1[5][5]; // an array of 5 rows of 5 ints.

typedef int Int5Array[5];  // type is an array of 5 ints
Int5Array ar2[5];          // an array of 5 Int5Arrays.

Maintenant la partie arithmétique du pointeur. Tout comme un pointeur de structure typé peut être avancé par la taille de la structure en octets, une dimension complète d'un tableau peut également être survolée. C’est plus facile à comprendre si vous pensez au tableau multi-dimensionné comme j’ai déclaré ar2 ci-dessus:

int (*arptr)[5] = ar1; // first row, address of ar1[0][0].
++arptr;               // second row, address of ar[1][0].

Tout cela s'en va avec un pointeur nu:

int *ptr = ar1; // first row, address of ar1[0][0].
++ptr;          // first row, address of ar1[0][1].

Par conséquent, lorsque vous effectuez l'arithmétique de pointeur pour un tableau à deux dimensions, les opérations suivantes NE fonctionneraient PAS pour obtenir l'élément à [2][2] d'un tableau à plusieurs dimensions:

#define NUMBER_OF_COLUMNS   5
int y[5][NUMBER_OF_COLUMNS];
int x = *(y + 2 * NUMBER_OF_COLUMNS + 2); // WRONG

La raison est heureusement évidente lorsque vous vous souvenez que y est un tableau de tableaux (de manière déclarative). L'arithmétique du pointeur consistant à ajouter le scaler (2*5 + 2) à y ajoutera 12 rows, calculant ainsi une adresse équivalente à &(y[12]), ce qui n'est clairement pas correct, et en fait, enverra un gros avertissement au moment de la compilation ou échouera complètement compiler tout à fait. Ceci est évité avec la conversion de (int*)y et le type résultant de l'expression étant basé sur un pointeur nu vers int:

#define NUMBER_OF_COLUMNS   5
int y[5][NUMBER_OF_COLUMNS];
int x = *((int *)y + 2 * NUMBER_OF_COLUMNS + 2); // Right!
52
antonijn

La table

En C, les tableaux 2D sont des séries continues de lignes (pas comme en Pascal).
Lorsque nous créons une table d'entiers à 4 lignes et 5 colonnes: A 5*4 integer table.

Atteindre les éléments

Nous pouvons atteindre les elemnts avec:

int element = table[row-1][column-1];

Mais nous pouvons aussi le faire avec le code suivant:

int element = *(*(table+row-1)+column-1);

Dans ces exemples, row et column est compté à partir de 1, c'est la raison du -1.
Dans le code suivant, vous pouvez vérifier que les deux techniques sont correctes. Dans ce cas, nous comptons les lignes et les colonnes de 0.

Exemple

#include <stdio.h>
#include <stdlib.h>
#define HEIGHT 4
#define WIDTH 5

int main()
{
    int table[HEIGHT][WIDTH] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
    int row = 2;
    int column = 2;
    int a = *(*(table+row)+column);
    printf("%d\n",a);//13
    printf("%d\n",table[row][column]);//13
    return 0;
}

Explication

Il s’agit d’une arithmétique en double pointeur, donc table pointe sur la première ligne et *table sur le premier élément. Si vous le déréférez, **table renvoie la valeur du premier élément. Dans l'exemple suivant, vous pouvez voir que *table et table pointent vers la même adresse mémoire.

printf("%d\n",table);//2293476
printf("%d\n",*table);//2293476
printf("%d\n",**table);//1

En mémoire, toutes les lignes de la table se suivent. Étant donné que table pointant sur la première ligne si nous ajoutons le numéro de ligne où l'élément requis est dans la table, nous obtiendrons un pointeur qui pointe vers cette ligne. Dans ce cas, *(table+row) contiendra une adresse pour le premier élément de la ligne donnée. Nous devons maintenant ajouter le numéro de colonne comme *(table+row)+column, et nous obtenons l'adresse de l'élément dans la ligne et la colonne données. Si on déduit cela, on obtient la valeur exacte de cet élément.
Donc, si nous comptons les lignes et les colonnes à partir de zéro, nous pouvons obtenir des éléments de la table comme ceci:

int element = *(*(table+row)+column);

En mémoire

The table in the memory.

23
totymedli

Un tableau 2D est considéré comme un tableau de tableaux 1D. C'est-à-dire que chaque ligne d'un tableau 2D est un tableau 1D. Par conséquent, étant donné un tableau 2D A,

int A[m][n].

En général,

A[i][j] = *(A[i]+j) 

également 

A[i] = *(A+i)

alors, 

A[i][j] = *(A[i]+j) = * ( *(A+i)+j).
18
nbs

Les réponses précédentes étaient déjà très bien expliquées, Je voudrais juste lister les expressions de pointeur selon ma compréhension, et les comparer avec le arr [i] [j] format.

 Expression du pointeur de 2-D  tableau: 
 le nom du tableau lui-même est un pointeur sur le premier sous-tableau, 

 arr: 
 sera le pointeur sur le premier sous-tableau, pas le premier élément du premier sous-
 tableau, en fonction de la relation entre tableau et pointeur, il représente également 
 le tableau lui-même, 

 arr + 1: 
 sera le pointeur sur le deuxième sous-tableau, pas sur le deuxième élément du premier sous-
 tableau, 

 * (arr + 1): 
 sera le pointeur sur le premier élément du deuxième sous-tableau, 
 selon la relation entre le tableau et le pointeur, il représente également la seconde 
 sous tableau, identique à arr [1], 

 * (arr + 1) +2: 
 sera le pointeur sur le troisième élément du deuxième sous-tableau, 

 * (* (arr + 1) +2): 
 obtiendra la valeur du troisième élément du deuxième sous-tableau, 
 pareil que arr [1] [2], 

Similaire au tableau 2-D, plusieurs D tableau a une expression similaire.

6
Eric Wang

Un moyen pratique d'accéder avec un pointeur.

typedef struct
{
    int  Array[13][2];
} t2DArray;

t2DArray TwoDArray =
{
   { {12,5},{4,8},{3,6},{7,9},{3,2},{3,3},{3,4},{3,5},{3,6},{3,7},{4,0},{5,0},{5,1} }
};

t2DArray *GetArray;

int main()
{
    GetArray = &TwoDArray;
    printf("\n %d\n %d\n %d\n %d\n %d\n %d\n",
    GetArray->Array[0][0], 
    GetArray->Array[0][1], 
    GetArray->Array[1][0], 
    GetArray->Array[1][1], 
    GetArray->Array[2][0], 
    GetArray->Array[2][1]);

    getchar();
    return 0;
}

EN DEHORS

12 5 4 8 3 6

2
CTastan
#include <iostream>
using namespace std;

int main()
{
   //FOR 1-D ARRAY THROUGH ARRAY
   int brr[5]= {1,2,3,4,5};

   for(int i=0; i<5; i++)
   {
      cout<<"address ["<<i<<"] = "  <<&brr[i]<<" and value = "<<brr[i]<<endl;        
   }

   //FOR 1-D ARRAY THROUGH POINTER
   cout<<endl;  //  endl TO MAKE OUT PUT LOOK CLEAR AND COOL :)
   int (*q)=brr;

   for(int i=0; i<5; i++)
   {
      cout<<"address ["<<i<<"] = "  <<&brr[i]<<" and value = "<<*(q+i)<<endl; //(p[i][j])
   }

   cout<<endl;

   //FOR 2-D ARRAY THROUGH ARRAY        
   int arr[2][3] = {1,2,3,4,5,6};

   for(int i=0; i<2; i++)
   {
      for(int j=0; j<3; j++)
      {
         cout<<"address ["<<i<<"]["<<j<<"] = "  <<&arr[i][j]<<" and value = "<<arr[i][j]<<endl;
      }
   }

   //FOR 2-D ARRAY THROUGH POINTER        
   int (*p)[3]=arr; //  j value we give
   cout<<endl;

   for(int i=0; i<2; i++)
   {
      for(int j=0; j<3; j++)
      {
         cout<<"address ["<<i<<"]["<<j<<"] = "  <<(*(p+i)+j)<<" and value = "<<(*(*(p+i)+j))<<endl; //(p[i][j])
      }
   }
   return 0;
}

==============OUT PUT======================

//FOR 1-D ARRAY THROUGH ARRAY

address [0] = 0x28fed4 and value = 1
address [1] = 0x28fed8 and value = 2
address [2] = 0x28fedc and value = 3
address [3] = 0x28fee0 and value = 4
address [4] = 0x28fee4 and value = 5

//FOR 1-D ARRAY THROUGH POINTER

address [0] = 0x28fed4 and value = 1
address [1] = 0x28fed8 and value = 2
address [2] = 0x28fedc and value = 3
address [3] = 0x28fee0 and value = 4
address [4] = 0x28fee4 and value = 5

//FOR 2-D ARRAY THROUGH ARRAY

address [0][0] = 0x28fee8 and value = 1
address [0][1] = 0x28feec and value = 2
address [0][2] = 0x28fef0 and value = 3
address [1][0] = 0x28fef4 and value = 4
address [1][1] = 0x28fef8 and value = 5
address [1][2] = 0x28fefc and value = 6

//FOR 2-D ARRAY THROUGH POINTER

address [0][0] = 0x28fee8 and value = 1
address [0][1] = 0x28feec and value = 2
address [0][2] = 0x28fef0 and value = 3
address [1][0] = 0x28fef4 and value = 4
address [1][1] = 0x28fef8 and value = 5
address [1][2] = 0x28fefc and value = 6
0
ankit gupta