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 …)
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 nichtuint8_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
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
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
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 !
:aWarum nichta[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
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
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
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
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
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
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
@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