wake-up-neo.com

Wie verwende ich Zeigerausdrücke, um auf Elemente eines zweidimensionalen Arrays in C zuzugreifen?

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?

35
Tudor Ciotlos

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:

  1. 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.

  2. 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!
52
antonijn

Der Tisch

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: A 5*4 integer table.

Die Elemente erreichen

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.

Beispiel

#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;
}

Erläuterung

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);

In der Erinnerung

The table in the memory.

23
totymedli

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).
18
nbs

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.

6
Eric Wang

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;
}

AUS

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