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 vom inkompatiblen Zeigertyp
- indizierter Wert ist weder Feld noch ein Zeiger
- Fehler: Ungültige Verwendung des flexiblen Array-Mitglieds
Antworten:
Hier möchten Sie einen Zeiger auf das erste Element des Arrays erstellen
Mit typedef sieht das sauberer aus
Dann kannst du das Leben wieder genießen :)
Hüten Sie sich vor der Zeiger- / Array-Welt in C, da herrscht große Verwirrung.
Bearbeiten
Überprüfen Sie einige der anderen Antworten hier, da die Kommentarfelder zu kurz sind, um sie dort auszuführen. Es wurden mehrere Alternativen vorgeschlagen, aber es wurde nicht gezeigt, wie sie sich verhalten. So machen sie es
Wenn Sie den Fehler beheben und die Adresse des Operators
&
wie im folgenden Snippet hinzufügenDann erstellt dieser einen Zeiger auf einen unvollständigen Array-Typ von Elementen vom Typ Array von 20 uint8_t. Da sich der Zeiger auf ein Array von Arrays befindet, müssen Sie mit darauf zugreifen
Und weil es ein Zeiger auf ein unvollständiges Array ist, können Sie es nicht als Verknüpfung verwenden
Da für die Indizierung die Größe des Elementtyps bekannt sein muss (die Indizierung impliziert das Hinzufügen einer Ganzzahl zum Zeiger, sodass dies bei unvollständigen Typen nicht funktioniert). Beachten Sie, dass dies nur funktioniert , in
C
, weilT[]
undT[N]
kompatible Typen sind. C ++ hat kein Konzept von kompatibelen Typen , und so ist es , dass Code ablehnen, weilT[]
undT[10]
verschiedene Arten sind.Die folgende Alternative funktioniert überhaupt nicht, da der Elementtyp des Arrays, wenn Sie es als eindimensionales Array betrachten, dies nicht
uint8_t
istuint8_t[20]
Das Folgende ist eine gute Alternative
Sie greifen mit darauf zu
Es hat den Vorteil, dass die Größe der äußeren Abmessung erhalten bleibt. Sie können also sizeof darauf anwenden
Es gibt eine andere Antwort, die die Tatsache nutzt, dass Elemente in einem Array zusammenhängend gespeichert werden
Damit können Sie formal nur auf die Elemente des ersten Elements des zweidimensionalen Arrays zugreifen. Das heißt, die folgende Bedingung gilt
Sie werden feststellen, dass es wahrscheinlich funktioniert
10*20-1
, aber wenn Sie Alias-Analysen und andere aggressive Optimierungen verwenden, könnte ein Compiler eine Annahme treffen, die diesen Code möglicherweise beschädigt. Trotzdem 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 selbst in den C-FAQ ist diese Technik enthalten (mit einer Warnung über seine UB'ness) ), und wenn Sie den Array-Typ nicht ändern können, ist dies eine letzte Option, um Sie zu speichern :)quelle
uint8_t *d[20]
, wodurch ein Array von 3 Zeigern auf uint8_t erstellt wird, aber das würde in diesem Fall nicht funktionieren.Um dies vollständig zu verstehen, müssen Sie die folgenden Konzepte verstehen :
Arrays sind keine Zeiger!
Erstens (und es wurde genug gepredigt) sind Arrays keine Zeiger . Stattdessen "zerfallen" sie in den meisten Fällen in die Adresse ihres ersten Elements, das einem Zeiger zugewiesen werden kann:
Ich gehe davon aus, dass es 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 bedeuten, 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.
Zum Beispiel
int a[4][3][5]
= ein Array, das 4 * 3 * 5 (60) 'Chunks' von ganzzahligem Speicher enthält.Der Vorteil gegenüber der Verwendung von
int a[4][3][5]
vs plainint b[60]
besteht darin, dass sie jetzt "partitioniert" sind (bei Bedarf einfacher mit ihren "Chunks" zu arbeiten) und das Programm nun gebundene Überprüfungen durchführen kann.Tatsächlich
int a[4][3][5]
wird genau wieint b[60]
im Speicher gespeichert - Der einzige Unterschied besteht darin, dass das Programm es jetzt so verwaltet, als ob es sich um separate Entitäten bestimmter Größen handelt (insbesondere vier Gruppen zu drei Gruppen zu je fünf).Denken Sie daran: Beide
int a[4][3][5]
undint b[60]
sind im Speicher gleich, und der einzige Unterschied besteht darin, wie sie von der Anwendung / dem Compiler behandelt werdenDaraus können Sie deutlich erkennen, dass jede "Partition" nur ein Array ist, das das Programm verfolgt.
Syntax
Jetzt unterscheiden sich Arrays syntaktisch von Zeigern . Dies bedeutet insbesondere, dass der Compiler / die Maschine sie unterschiedlich behandelt. Dies mag wie ein Kinderspiel erscheinen, aber sehen Sie sich Folgendes an:
Im obigen Beispiel wird dieselbe Speicheradresse zweimal wie folgt gedruckt:
Einem Zeiger kann jedoch nur einer so direkt zugewiesen werden :
Warum kann kein
a
Zeiger zugewiesen werden, kann es abera[0]
?Dies ist einfach eine Folge mehrdimensionaler Arrays, und ich werde erklären, warum:
Auf der Ebene von '
a
' sehen wir immer noch, dass wir eine andere 'Dimension' haben, auf die wir uns freuen können. Auf der Ebene von 'a[0]
' befinden wir uns jedoch bereits in der obersten Dimension, was das Programm betrifft, betrachten wir nur ein normales Array.Sie fragen sich vielleicht:
Warum ist es wichtig, wenn das Array mehrdimensional ist, um einen Zeiger dafür zu erstellen?
Es ist am besten, so zu denken:
Ein "Zerfall" von einem mehrdimensionalen Array ist nicht nur eine Adresse, sondern eine Adresse mit Partitionsdaten (AKA versteht immer noch, dass die zugrunde liegenden Daten aus anderen Arrays bestehen), die aus Grenzen besteht, die vom Array über die erste Dimension hinaus festgelegt werden.
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.
Beachten Sie auch die Verwendung von Klammern um
*p
:int (*p)[5][95][8]
- Dies bedeutet, dass wir einen Zeiger mit diesen Grenzen erstellen, nicht ein Array von Zeigern mit diesen Grenzen:int *p[5][95][8]
Fazit
Lassen Sie uns überprüfen:
Kurz gesagt: Mehrdimensionale Arrays zerfallen in Adressen, die den Inhalt verstehen können.
quelle
int *p1 = &(a[0]); // RIGHT !
Eigentlich ist es identisch mitint *p1 = a;
Im
Sie können gerne darauf zugreifen
Immerhin werden zweidimensionale Arrays auch als 1-d gespeichert.
quelle
Tag auch,
Die Erklärung
hat Speicher für 10 Zeilen mit 20 unit8_t-Positionen reserviert, dh 200 uint8_t-Positionen, wobei jedes Element durch Berechnung von 20 x Zeile + Spalte gefunden wird.
Also nicht
Geben Sie an, was Sie benötigen, und zeigen Sie auf das Element der Spalte Null in der ersten Zeile des Arrays.
Bearbeiten: Wenn Sie etwas weiter darüber nachdenken, ist ein Array-Name per Definition kein Zeiger? Das heißt, der Name eines Arrays ist ein Synonym für die Position des ersten Elements, dh l_matrix [0] [0]?
Edit2: Wie von anderen erwähnt, ist der Kommentarbereich für weitere Diskussionen etwas zu klein. Wie auch immer:
bietet keine Speicherzuweisung für das betreffende Array.
Wie oben erwähnt und wie in der Norm definiert, lautet die Aussage:
hat 200 aufeinanderfolgende Speicherorte vom Typ uint8_t reserviert.
Verweis auf l_matrix unter Verwendung von Anweisungen der Form:
gibt Ihnen den Inhalt des colno'ten Elements in Zeile rowno.
Dies ist auch der Fall, wenn eine Auffüllung oder Verschiebung der Byte-Ausrichtung an der Speicherung des vorliegenden Objekts beteiligt ist. Der Compiler passt diese automatisch an. Per Definition des C ANSI-Standards.
HTH
Prost,
quelle
In C99 (unterstützt von clang und gcc) gibt es eine obskure Syntax zum Übergeben mehrdimensionaler Arrays an Funktionen als Referenz:
Im Gegensatz zu einem einfachen Zeiger weist dies auf die Arraygröße hin, sodass der Compiler theoretisch vor dem Übergeben eines zu kleinen Arrays warnen und einen offensichtlichen Zugriff außerhalb der Grenzen erkennen kann.
Leider wird es nicht behoben
sizeof()
und Compiler scheinen diese Informationen noch nicht zu verwenden, so dass es eine Kuriosität bleibt.quelle
static 10
ist eine Art Garantie dafür, dass mindestens 10 Elemente vorhanden sind, was wiederum bedeutet, dass die Größe nicht festgelegt ist.static
, dass das Array ohne das Schlüsselwort nicht als Referenz übergeben würde, was nicht wahr ist. Arrays werden ohnehin als Referenz übergeben. Die ursprüngliche Frage bezog sich auf einen anderen Anwendungsfall - den Zugriff auf Elemente eines 2D-Arrays mithilfe eines zusätzlichen Zeigers innerhalb derselben Funktion / demselben Namespace.Sie können jederzeit vermeiden, mit dem Compiler herumzuspielen, indem Sie das Array als linear deklarieren und die Berechnung des Array-Index (Zeile, Spalte) selbst durchführen.
Das hätte der Compiler sowieso getan.
quelle
Die grundlegende Syntax zum Initialisieren des Zeigers, der auf ein multidimentionales Array verweist, lautet
type (*pointer)[1st dimension size][2nd dimension size][..] = &array_name
Die grundlegende Syntax für den Aufruf lautet
Hier ist ein Beispiel:
Ausgabe ist:
Es funktionierte...
quelle
Sie können es so machen:
quelle
Sie möchten einen Zeiger auf das erste Element, also;
quelle
Sie können auch einen Offset hinzufügen, wenn Sie negative Indizes verwenden möchten:
Wenn Ihr Compiler einen Fehler oder eine Warnung ausgibt, können Sie Folgendes verwenden:
quelle
c
, daher sollte die Antwort in derselben Sprache sein. Bitte beachten Sie die Tags.