Erstellen Sie einen Zeiger auf ein zweidimensionales Array

Lesezeit: 12 Minuten

Benutzeravatar von Dill
Dill

Ich brauche einen Zeiger auf ein statisches zweidimensionales Array. Wie wird das gemacht?

static uint8_t l_matrix[10][20];

void test(){
   uint8_t **matrix_ptr = l_matrix; //wrong idea 
}

Ich bekomme alle Arten von Fehlern wie:

  • Warnung: Zuweisung von inkompatiblem Zeigertyp
  • indizierter Wert ist weder Feld noch ein Zeiger
  • Fehler: Ungültige Verwendung eines flexiblen Array-Mitglieds

  • @JohannesSchaub-litb Das gibt es nicht mehr. (Wie kann ich es wieder anzeigen …? I kennt Mitglieder mit niedrigen Wiederholungszahlen können es anzeigen, aber ich habe vergessen, wie …)

    – Mateen Ulhaq

    21. Oktober 2011 um 4:49 Uhr


  • @muntoo: Hier ist eine Kopie davon: gist.github.com/sharth/ede13c0502d5dd8d45bd

    – Bill Lynch

    6. September 2013 um 16:13 Uhr

Johannes Schaub - Benutzerbild der litb
Johannes Schaub – litb

Hier möchten Sie einen Zeiger auf das erste Element des Arrays erstellen

uint8_t (*matrix_ptr)[20] = l_matrix;

Mit typedef sieht das sauberer aus

typedef uint8_t array_of_20_uint8_t[20];
array_of_20_uint8_t *matrix_ptr = l_matrix;

Dann kannst du das Leben wieder genießen 🙂

matrix_ptr[0][1] = ...;

Hüten Sie sich vor der Pointer/Array-Welt in C, es herrscht viel Verwirrung darüber.


Bearbeiten

Überprüfen Sie einige der anderen Antworten hier, da die Kommentarfelder dort zu kurz sind. Es wurden mehrere Alternativen vorgeschlagen, aber es wurde nicht gezeigt, wie sie sich verhalten. Hier ist, wie sie es tun

uint8_t (*matrix_ptr)[][20] = l_matrix;

Wenn Sie den Fehler beheben und den address-of-Operator hinzufügen & wie im folgenden Ausschnitt

uint8_t (*matrix_ptr)[][20] = &l_matrix;

Dann erstellt dieser einen Zeiger auf einen unvollständigen Array-Typ von Elementen des Typs array of 20 uint8_t. Da der Zeiger auf ein Array von Arrays zeigt, müssen Sie mit darauf zugreifen

(*matrix_ptr)[0][1] = ...;

Und weil es ein Zeiger auf ein unvollständiges Array ist, müssen Sie kann nicht tun als Abkürzung

matrix_ptr[0][0][1] = ...;

Weil für die Indizierung die Größe des Elementtyps bekannt sein muss (die Indizierung impliziert das Hinzufügen einer ganzen Zahl zum Zeiger, sodass sie bei unvollständigen Typen nicht funktioniert). Beachten Sie, dass dies nur in funktioniert CWeil T[] und T[N] sind kompatible Typen. C++ hat kein Konzept von kompatible Typenund so wird dieser Code abgelehnt, weil T[] und T[10] sind verschiedene Arten.


Die folgende Alternative funktioniert überhaupt nicht, da der Elementtyp des Arrays, wenn Sie es als eindimensionales Array betrachten, ist nicht uint8_taber uint8_t[20]

uint8_t *matrix_ptr = l_matrix; // fail

Folgendes ist eine gute Alternative

uint8_t (*matrix_ptr)[10][20] = &l_matrix;

Du greifst darauf zu mit

(*matrix_ptr)[0][1] = ...;
matrix_ptr[0][0][1] = ...; // also possible now

Es hat den Vorteil, dass es die Größe der äußeren Dimension beibehält. Sie können also sizeof darauf anwenden

sizeof (*matrix_ptr) == sizeof(uint8_t) * 10 * 20

Es gibt eine andere Antwort, die sich die Tatsache zunutze macht, dass Elemente in einem Array zusammenhängend gespeichert werden

uint8_t *matrix_ptr = l_matrix[0];

Damit können Sie formal nur auf die Elemente des ersten Elements des zweidimensionalen Arrays zugreifen. Das heißt, die folgende Bedingung gilt

matrix_ptr[0] = ...; // valid
matrix_ptr[19] = ...; // valid

matrix_ptr[20] = ...; // undefined behavior
matrix_ptr[10*20-1] = ...; // undefined behavior

Sie werden feststellen, dass es wahrscheinlich bis zu funktioniert 10*20-1, aber wenn Sie die Aliasanalyse und andere aggressive Optimierungen einschalten, könnte ein Compiler eine Annahme treffen, die diesen Code beschädigen kann. Allerdings bin ich noch nie auf einen Compiler gestoßen, der darauf fehlschlägt (aber andererseits habe ich diese Technik nicht in echtem Code verwendet), und sogar die C-FAQ enthält diese Technik (mit einer Warnung vor ihrer UB-Nähe ), und wenn Sie den Array-Typ nicht ändern können, ist dies eine letzte Option, um Sie zu retten 🙂

  • +1 – nette Infos zum int[][20]

    Aufschlüsselung – das geht in C++ nicht

    – Faisal Vali

  • 27. Juni 2009 um 15:46 Uhr

    @litb, es tut mir leid, aber das ist falsch, da Ihre Lösung keine Speicherzuweisung für das Array vorsieht.

    – Rob Wells

  • 27. Juni 2009 um 18:11 Uhr

    @Rob, ich verstehe dich nicht ganz. die Speicherung erfolgt in all diesen Fällen durch das Array l_matix selbst. Die Zeiger auf sie werden dort gespeichert, wo sie in und als deklariert sind (Stack, statisches Datensegment, …).

    – Johannes Schaub – litb

  • 27. Juni 2009 um 19:32 Uhr

    Nur neugierig, warum brauchen wir die “&” -Adresse von l_matrix?

    – elektro

  • 28. März 2017 um 23:41 Uhr uint8_t *d[20]@Sohaib – nein, das erzeugt nur einen Zeiger. Sie haben es vielleicht verwechselt mit

    was ein Array von 3 Zeigern auf uint8_t erstellt, aber das würde in diesem Fall nicht funktionieren.

    – Palo

7. Juli 2018 um 0:59 Uhr
Benutzeravatar von Super Cat

Super Katze Zu völlig verstehe das, du muss

die folgenden Konzepte verstehen:

Arrays sind keine Zeiger! Zuallererst (und es wurde genug gepredigt),Arrays sind keine Zeiger

int a[] = {1, 2, 3};

int *p = a; // p now points to a[0]

. Stattdessen „zerfallen“ sie in den meisten Fällen zur Adresse ihres ersten Elements, das einem Zeiger zugewiesen werden kann:



Ich gehe davon aus, dass dies so funktioniert, dass auf den Inhalt des Arrays zugegriffen werden kann, ohne alle zu kopieren. Das ist nur ein Verhalten von Array-Typen und soll nicht implizieren, dass sie dasselbe sind.

Mehrdimensionale Arrays

Mehrdimensionale Arrays sind nur eine Möglichkeit, den Speicher so zu “partitionieren”, dass der Compiler / die Maschine ihn verstehen und bearbeiten kann. int a[4][3][5] Zum Beispiel,

= ein Array, das 4*3*5 (60) ‘Chunks’ von ganzzahligem Speicher enthält. int a[4][3][5] Der Vorteil gegenüber der Nutzung int b[60] gegen schlicht

ist, dass sie jetzt ‘partitioniert’ sind (einfachere Arbeit mit ihren ‘Chunks’, falls nötig) und das Programm jetzt eine gebundene Prüfung durchführen kann. int a[4][3][5] In der Tat, wird gelagert exakt int b[60] wie in Erinnerung – Die nur

Der Unterschied besteht darin, dass das Programm es jetzt so verwaltet, als wären sie separate Einheiten bestimmter Größe (insbesondere vier Gruppen von drei Gruppen von fünf). int a[4][3][5] Denken Sie daran: Beides int b[60] und

{
  {1, 2, 3, 4, 5}
  {6, 7, 8, 9, 10}
  {11, 12, 13, 14, 15}
}
{
  {16, 17, 18, 19, 20}
  {21, 22, 23, 24, 25}
  {26, 27, 28, 29, 30}
}
{
  {31, 32, 33, 34, 35}
  {36, 37, 38, 39, 40}
  {41, 42, 43, 44, 45}
}
{
  {46, 47, 48, 49, 50}
  {51, 52, 53, 54, 55}
  {56, 57, 58, 59, 60}
}

sind im Speicher gleich, und der einzige Unterschied besteht darin, wie sie von der Anwendung/dem Compiler gehandhabt werden



Daraus können Sie deutlich erkennen, dass jede “Partition” nur ein Array ist, das das Programm verfolgt.

Syntax Jetzt,Arrays unterscheiden sich syntaktisch von Zeigern . Konkret bedeutet dies der Compiler/die Maschine behandelt sie anders.

int a[3][3];

printf("%p %p", a, a[0]);

Das mag wie ein Kinderspiel erscheinen, aber schau dir das an:

0x7eb5a3b4 0x7eb5a3b4

Das obige Beispiel gibt dieselbe Speicheradresse zweimal aus, etwa so:Allerdings kann einem Pointer so direkt nur einer zugeordnet werden

int *p1 = a[0]; // RIGHT !

int *p2 = a; // WRONG !

: a Warum nicht a[0] einem Zeiger aber zugeordnet werden

kann?

Dies ist einfach eine Folge mehrdimensionaler Arrays, und ich werde erklären, warum:aAuf der Stufe von ‘a[0]“ sehen wir immer noch, dass wir uns auf eine weitere „Dimension“ freuen können. Auf der Stufe von ‘

‘ befinden wir uns jedoch bereits in der obersten Dimension, so dass wir, was das Programm betrifft, nur ein normales Array betrachten.

Sie fragen sich vielleicht:

Warum spielt es eine Rolle, ob das Array mehrdimensional ist, um einen Zeiger darauf zu erstellen?

Am besten so denken: Ein ‘Zerfall’ aus einem mehrdimensionalen Array ist nicht nur eine Adresse, sondern eine Adresse mit Partitionsdaten

(AKA versteht es immer noch, dass seine zugrunde liegenden Daten aus anderen Arrays bestehen), die aus Grenzen bestehen, die durch das Array über die erste Dimension hinaus festgelegt werden.

int a[4][5][95][8];

int (*p)[5][95][8];

p = a; // p = *a[0] // p = a+0

Diese ‘Partitions’-Logik kann nicht innerhalb eines Zeigers existieren, es sei denn, wir geben sie an:

Andernfalls geht die Bedeutung der Sortiereigenschaften des Arrays verloren. *pBeachten Sie auch die Verwendung von runden Klammern int (*p)[5][95][8] : int *p[5][95][8]



– Das soll angeben, dass wir einen Zeiger mit diesen Grenzen erstellen, kein Array von Zeigern mit diesen Grenzen:

Fazit

  • Lassen Sie uns überprüfen:
  • Arrays zerfallen zu Adressen, wenn sie im verwendeten Kontext keinen anderen Zweck haben
  • Mehrdimensionale Arrays sind nur Arrays von Arrays – Daher trägt die “verfallene” Adresse die Last von “Ich habe Unterdimensionen”. Bemaßungsdaten können nicht in einem Zeiger vorhanden seines sei denn, du gibst es ihm

.

  • Kurz gesagt: Mehrdimensionale Arrays zerfallen zu Adressen, die die Fähigkeit besitzen, ihren Inhalt zu verstehen. int *p1 = &(a[0]); // RIGHT !Der erste Teil der Antwort ist großartig, aber der zweite nicht. Das ist nicht richtig: int *p1 = a;

    eigentlich ist es identisch mit

    – 2501


  • 25. April 2016 um 9:12 Uhr

    @2501 Vielen Dank, dass Sie diesen Fehler entdeckt haben, ich habe ihn korrigiert. Ich kann nicht mit Sicherheit sagen, warum das Beispiel, das diese “Regel” definiert, sich ihr auch widersetzt. Erwähnenswert ist, dass, nur weil zwei Entitäten als Zeiger interpretiert werden können und denselben Wert liefern, dies nicht bedeutet, dass sie dieselbe Bedeutung haben.

    – Superkat


  • 29. April 2016 um 2:42 Uhr

    Nur der Compiler sieht Arrays und Zeiger anders. Während der Laufzeit degenerieren Arrays zu nichts als konstanten Zeigern.

    – John Strood

9. September 2021 um 17:21 Uhr
Sagars Benutzeravatar

Sagar

int *ptr= l_matrix[0];

Im

*p
*(p+1)
*(p+2)

Sie können wie zugreifen

  • *(p+k) schließlich werden auch 2-dimensionale Arrays als 1-d gespeichert. p[k]ist buchstäblich gerecht

    !

    – John Strood

9. September 2021 um 17:22 Uhr
Benutzeravatar von Rob Wells

Rob Wells

Tag auch,

static uint8_t l_matrix[10][20];

Die Erklärung

hat Speicherplatz für 10 Zeilen mit 20 unit8_t-Positionen reserviert, dh 200 uint8_t-große Positionen, wobei jedes Element durch Berechnung von 20 x Zeile + Spalte gefunden wird.

uint8_t (*matrix_ptr)[20] = l_matrix;

Also nicht

Ihnen geben, was Sie brauchen, und auf das Element der Spalte Null der ersten Zeile des Arrays zeigen? Bearbeiten:[0][0]Wenn wir etwas weiter darüber nachdenken, ist ein Array-Name nicht per Definition ein Zeiger? Das heißt, der Name eines Arrays ist ein Synonym für die Position des ersten Elements, dh l_matrix

? Edit2:

typedef uint8_t array_of_20_uint8_t[20];
array_of_20_uint8_t *matrix_ptr = l_matrix;

Wie von anderen erwähnt, ist der Kommentarbereich für weitere Diskussionen etwas zu klein. Wie auch immer:

stellt keine Speicherzuweisung für das betreffende Array bereit.

static uint8_t l_matrix[10][20];

Wie oben erwähnt, und wie von der Norm definiert, die Aussage:

hat 200 aufeinanderfolgende Stellen vom Typ uint8_t reserviert.

(*l_matrix + (20 * rowno) + colno)

Verweis auf l_matrix mit Anweisungen der Form:

gibt Ihnen den Inhalt des Elements colno’th aus, das in Zeile rowno zu finden ist.

Alle Zeigermanipulationen berücksichtigen automatisch die Größe des Objekts, auf das gezeigt wird. – K&R Abschnitt 5.4, S.103 Dies ist auch der Fall, wenn bei der Speicherung des vorliegenden Objekts eine Auffüllung oder Verschiebung der Byte-Ausrichtung beteiligt ist. Der Compiler passt sich automatisch an diese an.

Nach Definition des C ANSI-Standards.

HTH

Prost,
Benutzeravatar von Kornel

Kornel

int l_matrix[10][20];

void test(int matrix_ptr[static 10][20]) {
}

int main(void) {
    test(l_matrix);
}

In C99 (unterstützt von clang und gcc) gibt es eine obskure Syntax, um mehrdimensionale Arrays per Referenz an Funktionen zu übergeben: Im Gegensatz zu einem einfachen Zeiger gibt dies Hinweise auf die Array-Größe, theoretisch

ermöglicht dem Compiler, vor der Übergabe eines zu kleinen Arrays zu warnen und einen offensichtlichen Zugriff außerhalb der Grenzen zu erkennen. sizeof() Leider wird es nicht behoben

  • und Compiler scheinen diese Informationen noch nicht zu verwenden, also bleibt es eine Kuriosität. static 10 Diese Antwort ist irreführend: Das Argument macht das Argument nicht zu einem Array mit fester Größe, es ist immer noch ein Zeiger. ist eine Art Garantie dafür wenigstens

    Es sind 10 Elemente vorhanden, was wiederum bedeutet, dass die Größe nicht festgelegt ist.

    – blöd

  • 26. November 2016 um 13:04 Uhr @bluss Die Frage bezog sich auf einen Zeiger, daher sehe ich nicht, wie die Beantwortung mit einem Zeiger (Hinweis:per Referenz

    ) ist irreführend. Das Array hat aus Sicht der Funktion eine feste Größe, da der Zugriff auf Elemente jenseits dieser Grenzen undefiniert ist.

    – Körnel

  • 26. November 2016 um 19:03 Uhr

    Ich glaube nicht, dass der Zugriff über 10 hinaus undefiniert ist, ich kann nichts sehen, was darauf hindeutet.

    – blöd

  • 26. November 2016 um 23:11 Uhr staticDiese Antwort scheint dies ohne das Schlüsselwort vorzuschlagen

    , würde das Array nicht als Referenz übergeben, was nicht wahr ist. Arrays werden ohnehin per Referenz übergeben. Die ursprüngliche Frage bezog sich auf einen anderen Anwendungsfall – Zugriff auf Elemente eines 2D-Arrays mit einem zusätzlichen Zeiger innerhalb derselben Funktion/Namespace.

    – Palo

7. Juli 2018 um 0:43 Uhr
Benutzeravatar von gnosis

Gnosis

static uint8_t l_matrix[200];

void test(int row, int col, uint8_t val)

{

   uint8_t* matrix_ptr = l_matrix;
   matrix_ptr [col+y*row] = val; // to assign a value

}

Sie können immer vermeiden, mit dem Compiler herumzuspielen, indem Sie das Array als linear deklarieren und die Indexberechnung (Zeile, Spalte) zum Array selbst durchführen.

  • das hätte der Compiler sowieso getan. static 10 Diese Antwort ist irreführend: Das Argument macht das Argument nicht zu einem Array mit fester Größe, es ist immer noch ein Zeiger. ist eine Art Garantie dafür wenigstens

    Es sind 10 Elemente vorhanden, was wiederum bedeutet, dass die Größe nicht festgelegt ist.

    – blöd

  • 26. November 2016 um 13:04 Uhr @bluss Die Frage bezog sich auf einen Zeiger, daher sehe ich nicht, wie die Beantwortung mit einem Zeiger (Hinweis:per Referenz

    ) ist irreführend. Das Array hat aus Sicht der Funktion eine feste Größe, da der Zugriff auf Elemente jenseits dieser Grenzen undefiniert ist.

    – Körnel

  • 26. November 2016 um 19:03 Uhr

    Ich glaube nicht, dass der Zugriff über 10 hinaus undefiniert ist, ich kann nichts sehen, was darauf hindeutet.

    – blöd

  • 26. November 2016 um 23:11 Uhr staticDiese Antwort scheint dies ohne das Schlüsselwort vorzuschlagen

    , würde das Array nicht als Referenz übergeben, was nicht wahr ist. Arrays werden ohnehin per Referenz übergeben. Die ursprüngliche Frage bezog sich auf einen anderen Anwendungsfall – Zugriff auf Elemente eines 2D-Arrays mit einem zusätzlichen Zeiger innerhalb derselben Funktion/Namespace.

    – Palo

7. Juli 2018 um 0:43 Uhr
Benutzeravatar von MAChitgarha

MAChitgarha

type (*pointer)[1st dimension size][2nd dimension size][..] = &array_name

Die grundlegende Syntax zum Initialisieren eines Zeigers, der auf ein mehrdimensionales Array zeigt, lautet

(*pointer_name)[1st index][2nd index][...]

Die grundlegende Syntax für den Aufruf ist

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
   // The multidimentional array...
   char balance[5][100] = {
       "Subham",
       "Messi"
   };

   char (*p)[5][100] = &balance; // Pointer initialization...

   printf("%s\n",(*p)[0]); // Calling...
   printf("%s\n",(*p)[1]); // Calling...

  return 0;
}

Hier ist ein Beispiel:

Subham
Messi

Ausgabe ist:

1423360cookie-checkErstellen Sie einen Zeiger auf ein zweidimensionales Array

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

Privacy policy