Ich weiß, dass x=a[i]
für eindimensionale Arrays äquivalent zu x=*(a+i)
ist, aber wie kann ich mit Zeigern auf Elemente zweidimensionaler Arrays zugreifen?
Zusammenfassung: Wenn Sie ein mehrdimensionales Array als int [][]
definiert haben, ist x = y[a][b]
äquivalent zu x = *((int *)y + a * NUMBER_OF_COLUMNS + b);
Langweilige Details:
Die (int *)
-Besetzung von y
verdient eine Erklärung, da ihre Notwendigkeit möglicherweise nicht intuitiv ist. Um zu verstehen, warum es dort sein muss, bedenken Sie Folgendes:
Die typisierte Zeigerarithmetik in C/C++ passt den typisierten Zeigerwert (der eine Adresse ist) beim Hinzufügen/Subtrahieren/Inkrementieren/Dekrementieren mit dem Skalar immer um die Größe des Bytes type in Bytes an.
Das grundlegende type einer mehrdimensionalen Array-Deklaration (nicht der Elementtyp; der variable -Typ) ist ein Array-Typ mit einer Dimension kleiner als der endgültigen Dimension.
Letzteres (Nr. 2) braucht wirklich ein Beispiel, um sich zu verfestigen. Im Folgenden sind die Variablen ar1
und ar2
äquivalente Deklarationen.
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.
Nun der Zeiger-Arithmetik-Teil. So wie ein typisierter Strukturzeiger um die Größe der Struktur in Bytes erweitert werden kann, kann auch eine vollständige Dimension eines Arrays übersprungen werden. Dies ist einfacher zu verstehen, wenn Sie an das mehrdimensionierte Array denken, wie ich es oben von ar2 erklärt habe:
int (*arptr)[5] = ar1; // first row, address of ar1[0][0].
++arptr; // second row, address of ar[1][0].
All dies geht mit einem bloßen Zeiger weg:
int *ptr = ar1; // first row, address of ar1[0][0].
++ptr; // first row, address of ar1[0][1].
Wenn Sie also die Zeigerarithmetik für ein zweidimensionales Array durchführen, funktioniert Folgendes NICHT, wenn Sie das Element [2][2]
eines mehrdimensionalen Arrays abrufen:
#define NUMBER_OF_COLUMNS 5
int y[5][NUMBER_OF_COLUMNS];
int x = *(y + 2 * NUMBER_OF_COLUMNS + 2); // WRONG
Der Grund ist hoffentlich offensichtlich, wenn Sie sich daran erinnern, dass y
ein Array von Arrays ist (deklarativ gesprochen). Die Zeigerarithmetik des Hinzufügens des Skalierers (2*5 + 2)
zu y
fügt 12 Zeilen hinzu, wobei die Berechnung und Adresse äquivalent zu &(y[12])
ist, was eindeutig nicht richtig ist, und in der Tat entweder eine fette Warnung zur Kompilierzeit auslöst oder es völlig fehlschlägt zusammen kompilieren. Dies wird mit der Umwandlung von (int*)y
und dem resultierenden Typ des Ausdrucks vermieden, der auf einem bloßen Zeiger auf int basiert:
#define NUMBER_OF_COLUMNS 5
int y[5][NUMBER_OF_COLUMNS];
int x = *((int *)y + 2 * NUMBER_OF_COLUMNS + 2); // Right!
In C 2D-Arrays sind fortlaufende Reihen von Zeilen (nicht wie in Pascal).
Wenn wir eine Tabelle mit Ganzzahlen mit 4 Zeilen und 5 Spalten erstellen:
Wir können die Elemente erreichen mit:
int element = table[row-1][column-1];
Das können wir aber auch mit folgendem Code:
int element = *(*(table+row-1)+column-1);
In diesen Beispielen wird row
und column
von 1 gezählt, das ist der Grund für -1.
Im folgenden Code können Sie testen, ob beide Techniken korrekt sind. In diesem Fall zählen wir die Zeilen und Spalten von 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;
}
Dies ist eine Double-Poiner-Arithmetik, daher zeigt table
auf die erste Zeile und *table
auf das erste Element. Wenn Sie es verwerfen, gibt **table
den Wert des ersten Elements zurück. Im folgenden Beispiel sehen Sie, dass *table
und table
auf dieselbe Speicheradresse zeigen.
printf("%d\n",table);//2293476
printf("%d\n",*table);//2293476
printf("%d\n",**table);//1
Im Speicher folgen alle Zeilen der Tabelle aufeinander. Da table
auf die erste Zeile zeigt, wenn wir die Zeilennummer hinzufügen, an der sich das benötigte Element in der Tabelle befindet, erhalten wir einen Zeiger, der auf diese Zeile zeigt. In diesem Fall enthält *(table+row)
eine Adresse zum ersten Element der angegebenen Zeile. Jetzt müssen wir nur noch die Spaltennummer wie *(table+row)+column
hinzufügen, und wir erhalten die Adresse des Elements in der angegebenen Zeile und Spalte. Wenn wir dies zurückweisen, erhalten wir den genauen Wert dieses Elements.
Wenn wir also die Zeilen und Spalten von Null aus zählen, können wir Elemente aus der Tabelle wie folgt abrufen:
int element = *(*(table+row)+column);
Ein 2D-Array wird als Array von 1D-Arrays betrachtet. Das heißt, jede Zeile in einem 2D-Array ist ein 1D-Array. Daher ist ein 2D-Array A
gegeben,
int A[m][n].
Im Algemeinen,
A[i][j] = *(A[i]+j)
ebenfalls
A[i] = *(A+i)
so,
A[i][j] = *(A[i]+j) = * ( *(A+i)+j).
Die vorherigen Antworten haben bereits sehr gut erklärt. Ich würde einfach Zeigerausdrücke nach meinem Verständnis auflisten und sie mit dem vergleichen arr [i] [j] Format.
Zeigerausdruck von 2-D Array: Der Arrayname selbst ist ein Zeiger auf das erste Subarray arr: wird ein Zeiger auf das erste Unterfeld, nicht das erste Element des ersten Unterelements Array, entsprechend der Beziehung von Array und Zeiger, repräsentiert es auch das Array selbst arr + 1: wird Zeiger auf das zweite Unterfeld, nicht das zweite Element des ersten Unterelements Array, * (arr + 1): wird ein Zeiger auf das erste Element des zweiten Sub-Arrays, Entsprechend der Beziehung von Array & Pointer repräsentiert es auch das zweite Subarray, gleich wie arr [1], * (arr + 1) +2: wird Zeiger auf das dritte Element des zweiten Unterfelds, * (* (arr + 1) +2): wird den Wert des dritten Elements des zweiten Unterfelds gleich wie arr [1] [2],
Ähnlich einem 2-D-Array multiple-D Array hat einen ähnlichen Ausdruck.
Eine praktische Möglichkeit, mit einem Zeiger zuzugreifen.
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