In C weiß ich, dass ich ein zweidimensionales Array auf dem Heap mithilfe des folgenden Codes dynamisch zuordnen kann:
int** someNumbers = malloc(arrayRows*sizeof(int*));
for (i = 0; i < arrayRows; i++) {
someNumbers[i] = malloc(arrayColumns*sizeof(int));
}
Dies erzeugt eindeutig ein eindimensionales Array von Zeigern auf eine Reihe separater eindimensionaler Arrays von ganzen Zahlen, und "The System" kann herausfinden, was ich meine, wenn ich frage:
someNumbers[4][2];
Aber wenn ich statisch ein 2D-Array deklariere, wie in der folgenden Zeile ...:
int someNumbers[ARRAY_ROWS][ARRAY_COLUMNS];
... wird eine ähnliche Struktur auf dem Stapel erstellt oder hat sie eine vollständig andere Form? (dh ist es ein 1D-Array von Zeigern? Wenn nicht, was ist es und wie werden Verweise darauf herausgefunden?)
Und als ich "The System" sagte, was ist eigentlich dafür verantwortlich, das herauszufinden? Der Kernel? Oder sortiert der C-Compiler dies beim Kompilieren?
quelle
malloc()
nicht zu einem N-dimensionalen Array. . Es führt zu Arrays von Zeigern [zu Arrays von Zeigern [...]], um eindimensionale Arrays vollständig zu trennen . Weitere Informationen zum Zuweisen von TRUE N-dimensionalen Arrays finden Sie unter Richtiges Zuweisen mehrdimensionaler Arrays.Antworten:
Ein statisches zweidimensionales Array sieht aus wie ein Array von Arrays - es ist nur zusammenhängend im Speicher angeordnet. Arrays sind nicht dasselbe wie Zeiger, aber da Sie sie häufig austauschbar verwenden können, kann es manchmal verwirrend werden. Der Compiler behält jedoch den Überblick, wodurch alles gut ausgerichtet ist. Sie müssen mit statischen 2D-Arrays, wie Sie sie erwähnen, vorsichtig sein, denn wenn Sie versuchen, eines an eine Funktion zu übergeben, die einen
int **
Parameter verwendet, werden schlimme Dinge passieren. Hier ist ein kurzes Beispiel:Im Gedächtnis sieht es so aus:
genau das gleiche wie:
Wenn Sie jedoch versuchen,
array1
auf diese Funktion zuzugreifen:Sie erhalten eine Warnung (und die App kann nicht richtig auf das Array zugreifen):
Weil ein 2D-Array nicht dasselbe ist wie
int **
. Das automatische Zerfallen eines Arrays in einen Zeiger geht sozusagen nur "eine Ebene tief". Sie müssen die Funktion wie folgt deklarieren:oder
Um alles glücklich zu machen.
Das gleiche Konzept erstreckt sich auf n- dimensionale Arrays. Die Nutzung dieser Art von witzigem Geschäft in Ihrer Anwendung erschwert jedoch im Allgemeinen nur das Verständnis. Also sei da draußen vorsichtig.
quelle
sizeof(int[100]) != sizeof(int *)
100 * sizeof(int)
int
Die Antwort liegt auf der Idee , dass C nicht wirklich hat 2D - Arrays - es hat Arrays-of-Arrays. Wenn Sie dies deklarieren:
Sie möchten
someNumbers
ein Array von 4 Elementen sein, wobei jedes Element dieses Arrays vom Typ istint [2]
(was selbst ein Array von 2int
s ist).Der andere Teil des Puzzles besteht darin, dass Arrays immer zusammenhängend im Speicher angeordnet sind. Wenn Sie fragen nach:
dann wird das immer so aussehen:
(4
sometype_t
nebeneinander angeordnete Objekte ohne Zwischenräume). In IhremsomeNumbers
Array von Arrays sieht es also so aus:Und jedes
int [2]
Element ist selbst ein Array, das so aussieht:Insgesamt erhalten Sie also Folgendes:
quelle
int
im Array von Arrays erhalten (z. B. durch Auswertena[0]
oder&a[0][0]
), können Sie diesen versetzen, um nacheinander auf alle zuzugreifenint
.im Speicher ist gleich:
quelle
Als Antwort auf Ihre Frage auch: Beides, obwohl der Compiler den größten Teil des schweren Hebens erledigt.
Bei statisch zugewiesenen Arrays ist "The System" der Compiler. Der Speicher wird wie für jede Stapelvariable reserviert.
Im Fall des malloc'd-Arrays ist "The System" der Implementierer von malloc (normalerweise der Kernel). Der Compiler weist lediglich den Basiszeiger zu.
Der Compiler wird den Typ immer so behandeln, wie er deklariert ist, außer in dem Beispiel, das Carl gegeben hat, wo er die austauschbare Verwendung herausfinden kann. Wenn Sie ein [] [] an eine Funktion übergeben, muss davon ausgegangen werden, dass es sich um eine statisch zugewiesene Wohnung handelt, wobei ** als Zeiger auf Zeiger angenommen wird.
quelle
malloc
implementiert wird, ist nicht im Standard festgelegt und der Implementierung überlassen. Umgebung. Für freistehende Umgebungen ist es optional, wie alle Teile der Standardbibliothek, für die Verknüpfungsfunktionen erforderlich sind (dies führt tatsächlich zu den Anforderungen, nicht wörtlich zu den Angaben im Standard). In einigen modernen gehosteten Umgebungen basiert es in der Tat auf Kernelfunktionen, entweder auf dem gesamten Material oder (z. B. Linux), wie Sie es mit stdlib- und Kernel-Primitiven geschrieben haben. Für Einzelprozesssysteme mit nicht virtuellem Speicher kann nur stdlib verwendet werden.Nehmen wir an , wir haben
a1
unda2
definiert und initialisiert wie unter (c99):a1
ist ein homogenes 2D-Array mit einem einfachen kontinuierlichen Layout im Speicher, und der Ausdruck(int*)a1
wird als Zeiger auf sein erstes Element ausgewertet:a2
wird aus einem heterogenen 2D-Array initialisiert und ist ein Zeiger auf einen Wert vom Typint*
, dh der Dereferenzierungsausdruck wird*a2
zu einem Wert vom Typ ausgewertet. Dasint*
Speicherlayout muss nicht kontinuierlich sein:Trotz völlig unterschiedlicher Speicherlayouts und Zugriffssemantik sieht die C-Sprach-Grammatik für Array-Zugriffsausdrücke für homogene und heterogene 2D-Arrays genau gleich aus:
a1[1][0]
holt Wert144
ausa1
Arraya2[1][0]
holt Wert244
ausa2
ArrayDer Compiler weiß, dass der Zugriffsausdruck für den
a1
Typ bearbeitetint[2][2]
, wenn der Zugriffsausdruck für dena2
Typ bearbeitetint**
. Der generierte Assemblycode folgt der homogenen oder heterogenen Zugriffssemantik.Der Code stürzt normalerweise zur Laufzeit ab, wenn ein Array vom Typ
int[N][M]
typisiert und dann als Typ aufgerufen wirdint**
, zum Beispiel:quelle
Um auf ein bestimmtes 2D-Array zuzugreifen, betrachten Sie die Speicherzuordnung für eine Array-Deklaration wie im folgenden Code gezeigt:
Um auf jedes Element zuzugreifen, reicht es aus, nur das Array, an dem Sie interessiert sind, als Parameter an die Funktion zu übergeben. Verwenden Sie dann den Versatz für die Spalte, um auf jedes Element einzeln zuzugreifen.
quelle