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?
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:
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.
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!
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:
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.
#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;
}
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);
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).
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.
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;
}
12 5 4 8 3 6
#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