Warum können wir keinen Doppelzeiger verwenden, um zweidimensionale Arrays darzustellen?

Lesezeit: 7 Minuten

Benutzeravatar von Thangaraj
Thangaraj

Warum können wir keinen Doppelzeiger verwenden, um zweidimensionale Arrays darzustellen?

arr[2][5] = {"hello","hai"};
**ptr = arr;

Warum funktioniert der Doppelzeiger (**ptr) in diesem Beispiel nicht?

  • Welchen Code haben Sie kompiliert, der dem Code in Ihrer Frage ähnelt?

    – Steve Jessop

    17. Dezember 2010 um 13:40 Uhr

  • Laufen Sie weg von mehrdimensionalen Arrays (außer vielleicht kleinen).

    – Alexander C.

    17. Dezember 2010 um 13:42 Uhr

  • @Alexandre C. Mehrdimensionale Arrays sind einfach, nützlich und effizient. Warum willst du vor ihnen davonlaufen?

    – Shahbaz

    12. September 2011 um 12:22 Uhr

  • @Shahbaz: Sie sind nicht einfach, und wenn Sie kein C99 haben, sind sie auch nicht nützlich, da sie keine variable Länge haben können.

    – Alexander C.

    12. September 2011 um 17:58 Uhr

  • Ich habe die Frage umgedreht, damit zukünftige Leser nicht in die Irre geführt werden.

    – Shahbaz

    17. Oktober 2013 um 8:53 Uhr

Benutzeravatar von Shahbaz
Shahbaz

Ich werde versuchen zu zeichnen, wie

int array[10][6];

und

int **array2 = malloc(10 * sizeof *array2);
for (int i = 0; i < 10; ++i)
    array2[i] = malloc(6 * sizeof **array2);

wie sie in der Erinnerung aussehen und wie sie sich unterscheiden (und dass sie nicht aufeinander geworfen werden können)

array sieht aus wie:

 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| | | | | | | | | | | | | ..............| | | (10*6 elements of type int)
 - - - - - - - - - - - - - - - - - - - - - -
< first row >< second row> ...

array2 sieht aus wie:

 _ _ _ _ _ _ _ _ _ _ 
| | | | | | | | | | | (10 elements of type int *)
 - - - - - - - - - - 
 | |     ....      |     _ _ _ _ _ _
 | |                \-->| | | | | | | (6 elements of type int)
 | |                     - - - - - -
 | |
 | |      _ _ _ _ _ _
 |  \ -->| | | | | | | (6 elements of type int)
 |        - - - - - -
 |
 |
 |      _ _ _ _ _ _
  \ -->| | | | | | | (6 elements of type int)
        - - - - - -

Wenn du sagst array[x][y]übersetzt es in *((int *)array+x*6+y)

Während, wenn Sie sagen array2[x][y]übersetzt es in *(*(array2+x)+y) (Beachten Sie, dass für arraydiese Formel funktioniert auch (bis zum Ende des Beitrags lesen, dann die Kommentare)).

Das heißt, ein statisches 2D-Array ist tatsächlich ein 1D-Array mit Zeilen in einer Zeile. Der Index wird nach der Formel berechnet row * number_of_columns_in_one_row + column.

Ein dynamisches 2D-Array ist jedoch nur ein 1D-Array von Zeigern. Jeder Zeiger wird dann dynamisch zugewiesen, um auf ein anderes 1d-Array zu zeigen. In Wahrheit könnte dieser Zeiger alles sein. Könnte sein NULL, oder auf eine einzelne Variable oder auf ein anderes Array zeigen. Und jeder dieser Zeiger wird einzeln gesetzt, sodass sie unterschiedlicher Natur sein können.

Wenn Sie den Zeiger von übergeben müssen array irgendwohin kann man es nicht werfen int ** (stellen Sie sich vor, was passieren würde. Die int Werte der Zellen von array werden als Zeiger interpretiert und dereferenziert -> Bam! Segmentierungsfehler!). Kann man sich aber denken array als 1d-Array von int [6]s; das ist ein 1d-Array von Elementen mit Typ int [6]. Um das aufzuschreiben, sagst du

int (*p)[6] = array;

  • Wenn array wird im Speicher so zugewiesen, wie Sie es beschrieben haben etwas wie das funktioniert noch immer? das kann ich verstehen array[x][y] wird übersetzt in *(((int *)array)+x*6+y)aber warum tut *(*(array + i) + j) funktioniert noch immer?

    – Kohányi Robert

    6. September 2018 um 7:20 Uhr

  • @KohányiRóbert, das ist ein ausgezeichneter Punkt. Und tatsächlich für ein (nicht dynamisches) mehrdimensionales Array (array in diesem Fall) sind die beiden äquivalent. Dabei ist auf die Art zu achten array im Ausdruck, um es zu verstehen. Beachten Sie zuerst, dass in *(((int *)array)+x*6+y)warf ich zuerst array zu int *. Dies bedeutet im Wesentlichen x*6+y ist ein Index für ein Array von ints.

    – Shahbaz

    18. September 2018 um 14:55 Uhr

  • Jetzt, wenn du es tust *(*(array + i) + j))ändern Sie nicht den Typ von array. Was ist die Art von array? Es ist int (*)[6]. Was ist das sizeof davon? Es ist sizeof(int) * 6. Jetzt *(array + i) wird dann dasselbe wie (int[6])((int *)array + i*6) (macht Sinn?). Indiziert wird das mit j *((int *)array + i*6 + j).

    – Shahbaz

    18. September 2018 um 14:55 Uhr


  • Ist int *p[6] = array; auch gültig? Sind die Klammern für den Compiler von Bedeutung?

    – Rohan

    18. April 2020 um 9:53 Uhr


  • @ Rohan, die Klammern sind wichtig. int *p[6] ist ein Array von 6 Zeigern. int (*p)[6] ist ein Zeiger auf ein Array von 6 ganzen Zahlen. Dies ist Funktionszeigern ziemlich ähnlich. int *f() und int (*f)() sind verschiedene Dinge.

    – Shahbaz

    22. April 2020 um 2:53 Uhr


Benutzeravatar von Steve Jessop
Steve Jessop

In C ist ein zweidimensionales Array an Array von Arrays.

Sie benötigen einen Zeiger auf ein Array, um darauf zu verweisen, keinen Doppelzeiger:

char array[2][6] = {"hello", "hai"};
char (*p)[6] = array;
//char **x = array;  // doesn't compile.

Damit ein Doppelzeiger auf “2-dimensionale Daten” verweist, muss er auf das erste Element von an verweisen Array von Zeigern. Aber ein zweidimensionales Array in C (Array von Arrays) ist nicht dasselbe wie ein Array von Zeigern, und wenn Sie nur ein 2-D-Array definieren, dann existiert kein entsprechendes Array von Zeigern.

Die einzige Ähnlichkeit zwischen den beiden ist die [][] Syntax, mit der auf die Daten zugegriffen wird: Die Daten selbst sind ganz anders strukturiert.

Benutzeravatar von unwind
entspannen

Zeiger-zu-Zeiger zu haben bedeutet, dass jede Zeile (oder Spalte, wenn Sie es lieber so sehen) eine andere Länge als die anderen Zeilen/Spalten haben kann.

Sie können ein 2D-Array auch nur durch einen Zeiger auf das Startelement und eine ganze Zahl darstellen, die die Anzahl der Elemente pro Zeile/Spalte angibt:

void matrix_set(double *first, size_t row_size, size_t x, size_t y, double value)
{
  first[y * row_size + x] = value;
}

R.. GitHub STOP HELPING ICEs Benutzeravatar
R.. GitHub HÖREN SIE AUF, ICE ZU HELFEN

Erstellen eines Arrays von Zeigern auf jede Zeile, um ein Objekt zu erhalten, das “aussieht” wie ein mehrdimensionales Array variabler Größe ist eine teure Designentscheidung für syntaktischen Zucker. Tu es nicht.

Der richtige Weg, um ein mehrdimensionales Array variabler Größe zu erstellen, ist etwa so:

if (w > SIZE_MAX/sizeof *m/h) goto error;
m = malloc(w * h * sizeof *m);
if (!m) goto error;
...
m[y*w+x] = foo;

Wenn Sie möchten, dass es “hübsch aussieht”, können Sie schreiben m[y][x]sollten Sie eine andere Sprache verwenden, vielleicht C++.

Beginnen wir damit, über das Gesetzbuch zu sprechen. Was Sie geschrieben haben (unter der Annahme eines Zeichens vor jeder Deklaration) wird aus mehreren Gründen nicht kompiliert: Sie haben zu viele Initialisierer (sechs Zeichen für arr[0]und seine Größe ist 5), und natürlich hat char** p keinen Typ, der mit char arr kompatibel ist[2][5]. Korrigiert man diese Probleme, erhält man:

char arr[2][6] = { "hello", "hai" };
char (*p)[6] = arr;

Ohne Doppelzeiger. Wenn Sie oben auf einzelne Zeichen zugreifen möchten, müssen Sie das Element angeben, aus dem sie stammen:

char* pc = *arr;

würde funktionieren, wenn Sie auf Zeichen aus dem ersten Element in arr zugreifen möchten.

C++ hat keine zweidimensionalen Arrays. Die erste obige Definition definiert ein Array[2] oder Array[6] von Zeichen Die implizite Array-zu-Zeiger-Konvertierung führt zu einem Zeiger auf Array[6] von Zeichen Danach gibt es natürlich keine Array-zu-Zeiger-Konvertierung, weil Sie kein Array mehr haben.

Benutzeravatar von LinconFive
LincolnFive

Es gibt für immer eine Entkopplung von Sprache zu Repräsentation.

Bis zu einem gewissen Grad ist C fast Dissendium.

Nehmen Sie das obige Beispiel, wir versuchen, ein 2D-Array in eine andere Form zuzuweisen oder umzuwandeln.

#include <stdio.h> 
  
int main() 
{ 
        char array[2][6] = {"hello", "hai"};
        int h, i;
        for (h = 0; h < 2; h++) 
                for (i = 0; i < 6; i++) 
                        printf("%c\n", *(*(array+h) + i));
        char (*p)[6] = array;
        for (h = 0; h < 2; h++) 
                for (i = 0; i < 6; i++) 
                        printf("%c\n", *(*(p+h) + i));
        char **x = array;
        for (h = 0; h < 2; h++) 
                        printf("%c\n", *(x+h));
} 

Und die Ausgabe,

h
e
l
l
o

h
a
i



h
e
l
l
o

h
a
i



h
i

Heutzutage sind Compiler so schlau, dass sie wahrscheinlich nur warnen, anstatt zu scheitern, dh

main.c:14:13: warning: initialization from incompatible pointer type [enabled by default]
  char **x = array;

An dieser Stelle sollten wir in der Lage sein, Doppelzeiger zu verstehen ist nicht doppelte Anordnung.

Der Erste h ist von helloder Zweite i ist von hai. Beachten Sie, dass der Abstand 8 Bytes beträgt Größe eines Zeigers.

Außerdem können wir auch,

char *y[2];
for (h = 0; h < 2; h++) 
        y[h] = array[h];
for (h = 0; h < 2; h++)
        printf("%s\n", y[h]);
for (h = 0; h < 2; h++)
        for (i = 0; i < 6; i++)
                printf("%c\n", *(*(p+h) + i));

Aber diese Aufgabe ist nicht eine einzeilige Aussage.

Und die Ausgabe,

hello
hai
h
e
l
l
o

h
a
i

1390280cookie-checkWarum können wir keinen Doppelzeiger verwenden, um zweidimensionale Arrays darzustellen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy