In meinem Code:
char *str[] = {"forgs", "do", "not", "die"};
printf("%d %d", sizeof(str), sizeof(str[0]));
Ich bekomme die Ausgabe als 12 2
also meine zweifel sind:
- Warum gibt es einen Unterschied?
- Beide
str
und str[0]
sind Zeichenzeiger, richtig?
Durch die Frage wurde bereits beantwortet und akzeptiert, aber ich füge eine weitere Beschreibung hinzu (die auch die ursprüngliche Frage beantwortet), die meiner Meinung nach für neue Benutzer hilfreich sein wird. (wie ich gesucht habe, wird diese Beschreibung nirgendwo anders erklärt (zumindest bei Stackoverflow), daher füge ich sie jetzt hinzu.
Erst gelesen: sizeof
Operator
6.5.3.4 Der sizeof-Operator, 1125:
Beim Anwenden der sizeof
-Operator an einen Array-Typ, ist das Ergebnis die Gesamtzahl der Bytes im Array.
Demnach wann sizeof
wird auf den Namen eines statischen Array-Bezeichners (nicht zugewiesen durch malloc), ist das Ergebnis die Größe des gesamten Arrays in Bytes und nicht nur die Adresse. Dies ist eine der wenigen Ausnahmen von der Regel, dass der Name eines Arrays in einen Zeiger auf das erste Element des Arrays umgewandelt/zerfallen wird, und dies nur deshalb möglich ist, weil die tatsächliche Array-Größe festgelegt und zur Kompilierzeit bekannt ist sizeof
Betreiber wertet aus.
Um es besser zu verstehen, betrachten Sie den folgenden Code:
#include<stdio.h>
int main(){
char a1[6], // One dimensional
a2[7][6], // Two dimensional
a3[5][7][6]; // Three dimensional
printf(" sizeof(a1) : %lu \n", sizeof(a1));
printf(" sizeof(a2) : %lu \n", sizeof(a2));
printf(" sizeof(a3) : %lu \n", sizeof(a3));
printf(" Char : %lu \n", sizeof(char));
printf(" Char[6] : %lu \n", sizeof(char[6]));
printf(" Char[5][7] : %lu \n", sizeof(char[7][6]));
printf(" Char[5][7][6]: %lu \n", sizeof(char[5][7][6]));
return 1;
}
Seine Ausgabe:
sizeof(a1) : 6
sizeof(a2) : 42
sizeof(a3) : 210
Char : 1
Char[5] : 6
Char[5][7] : 42
Char[5][7][6]: 210
Überprüfen Sie oben arbeiten bei @CodepadBeachten Sie die Größe von char
ist ein Byte, es ersetzen Sie char
mit int
Im obigen Programm wird dann jede Ausgabe mit multipliziert sizeof(int)
auf Ihrer Maschine.
Unterschied zwischen char* str[]
und char str[][]
und wie beide im Gedächtnis gespeichert werden
Erklärung-1: char *str[] = {"forgs", "do", "not", "die"};
In dieser Erklärung str[]
ist ein Array von Zeigern zu char. Jeder Index str[i]
zeigt auf das erste Zeichen von Strings in {"forgs", "do", "not", "die"};
.
Logisch str
sollte im Speicher folgendermaßen angeordnet sein:
Array Variable: Constant Strings:
--------------- -----------------
str: 201 202 203 204 205 206
+--------+ +-----+-----+-----+-----+-----+-----+
343 | |= *(str + 0) | 'f' | 'o' | 'r' | 'g' | 's' | '\0'|
| str[0] |-------| +-----+-----+-----+-----+-----+-----+
| 201 | +-----------▲
+--------+ 502 503 504
| | +-----+-----+-----+
347 | str[1] |= *(str + 1) | 'd' | 'o' | '\0'|
| 502 |-------| +-----+-----+-----+
+--------+ +-----------▲
| | 43 44 45 46
351 | 43 | +-----+-----+-----+-----+
| str[2] |= *(str + 2) | 'n' | 'o' | 't' | '\0'|
| |-------| +-----+-----+-----+-----+
+--------+ +-----------▲
355 | |
| 9002 | 9002 9003 9004 9005
| str[3] | +-----+-----+-----+-----+
| |= *(str + 3) | 'd' | 'i' | 'e' | '\0'|
+--------+ | +-----+-----+-----+-----+
+-----------▲
Diagram: shows that str[i] Points to first char of each constant string literal.
Memory address values are assumption.
Notiz: str[]
wird in Continue-Speicherzuweisungen gespeichert und jede Zeichenfolge wird im Speicher an einer zufälligen Adresse gespeichert (nicht im Continue-Bereich).
[ANSWER]
Entsprechend Codepad folgender Code:
int main(int argc, char **argv){
char *str[] = {"forgs", "do", "not", "die"};
printf("sizeof(str): %lu, sizeof(str[0]): %lu\n",
sizeof(str),
sizeof(str[0])
);
return 0;
}
Ausgabe:
sizeof(str): 16, sizeof(str[0]): 4
-
In diesem Code str
ist ein Array für 4 char-Adressen, wo jede char*
hat eine Größe von 4 Bytes, also ist die Gesamtgröße des Arrays gemäß obigem Zitat 4 * sizeof(char*)
= 16 Byte.
-
Datentyp von str
ist char*[4]
.
-
str[0]
ist nichts als ein Zeiger auf char, also vier Bytes. Datumstyp von str[i]
ist char*
.
(Hinweis: In einigen Systemadressen kann es sich um 2-Byte oder 8-Byte handeln.)
Zur Ausgabe sollte man auch den Kommentar von glglgl zur Frage lesen:
Unabhängig von Ihrer Architektur sollte der erste Wert das 4-fache des zweiten sein. Auf einem 32-Bit-Rechner sollten Sie 16 4 erhalten, auf einem 64-Bit-Rechner 32 8. Auf einem sehr alten oder einem eingebetteten System erhalten Sie möglicherweise sogar 8 2, aber niemals 12 2, da das Array 4 Elemente von enthält gleiche Größe
Zusätzliche Punkte:
- Denn jeder
str[i]
weist auf a char*
(und string) ist variabel, str[i]
kann beispielsweise einer neuen Zeichenfolgenadresse zugewiesen werden: str[i] = "yournewname";
gilt für i = 0 to < 4
.
Noch ein wichtiger Hinweis:
-
In unserem obigen Beispiel str[i]
zeigt auf ein konstantes String-Literal, das nicht geändert werden kann; somit str[i][j] = 'A'
ist ungültig (wir können nicht in den Nur-Lese-Speicher schreiben) und dies zu tun, wird ein Laufzeitfehler sein.
Aber angenommen, wenn str[i]
zeigt dann auf ein einfaches char-Array str[i][j] = 'A'
kann ein gültiger Ausdruck sein.
Betrachten Sie folgenden Code:
char a[] = "Hello"; // a[] is simple array
char *str[] = {"forgs", "do", "not", "die"};
//str[0][4] = 'A'; // is error because writing on read only memory
str[0] = a;
str[0][5] = 'A'; // is perfectly valid because str[0]
// points to an array (that is not constant)
Überprüfen Sie hier den Arbeitscode: Codepad
Erklärung-2: char str[][6] = {"forgs", "do", "not", "die"};
:
Hier str
ist ein zweidimensionales Array von Zeichen (wobei jede Zeile gleich groß ist) der Größe 4 * 6. (Denken Sie daran, dass Sie hier den Spaltenwert in der Deklaration von angeben müssen str
ausdrücklich, aber Zeile ist 4, weil die Anzahl der Zeichenfolgen 4 ist)
In Erinnerung str[][]
wird so etwas wie unten im Diagramm sein:
str
+---201---202---203---204---205---206--+
201 | +-----+-----+-----+-----+-----+-----+|
str[0] = *(str + 0)--►| 'f' | 'o' | 'r' | 'g' | 's' | '\0'||
207 | +-----+-----+-----+-----+-----+-----+|
str[1] = *(str + 1)--►| 'd' | 'o' | '\0'| '\0'| '\0'| '\0'||
213 | +-----+-----+-----+-----+-----+-----+|
str[2] = *(str + 2)--►| 'n' | 'o' | 't' | '\0'| '\0'| '\0'||
219 | +-----+-----+-----+-----+-----+-----+|
str[3] = *(str + 3)--►| 'd' | 'i' | 'e' | '\0'| '\0'| '\0'||
| +-----+-----+-----+-----+-----+-----+|
+--------------------------------------+
In Diagram:
str[i] = *(str + i) = points to a complete i-row of size = 6 chars.
str[i] is an array of 6 chars.
Diese Anordnung des 2D-Arrays im Speicher wird aufgerufen Reihe-Major: Ein mehrdimensionales Array im linearen Speicher ist so organisiert, dass Zeilen nacheinander gespeichert werden. Es ist der Ansatz, der von der Programmiersprache C verwendet wird.
Beachten Sie die Unterschiede in beiden Diagrammen.
- Im zweiten Fall wird ein vollständiges zweidimensionales Zeichenfeld im Fortsetzungsspeicher allokiert.
- Für alle
i = 0 to 2
, str[i]
und str[i + 1]
Der Wert unterscheidet sich um 6 Bytes (das entspricht der Länge einer Zeile).
- Doppelte Begrenzungslinie in diesem Diagramm bedeutet
str
entspricht komplett 6 * 4 = 24 Zeichen.
Betrachten Sie nun einen ähnlichen Code, den Sie in Ihrer Frage für ein zweidimensionales Zeichenarray gepostet haben Codepad:
int main(int argc, char **argv){
char str[][6] = {"forgs", "do", "not", "die"};
printf("sizeof(str): %lu, sizeof(str[0]): %lu\n",
sizeof(str),
sizeof(str[0])
);
return 0;
}
Ausgabe:
sizeof(str): 24, sizeof(str[0]): 6
Laut dem sizeof
Behandlung des Operators mit Array, Bei Anwendung einer 2-D-Array-Größe von sollte die gesamte Array-Größe zurückgegeben werden, die 24 Byte beträgt.
-
Wie wir wissen, sizeof
Der Operator gibt die Größe des gesamten Arrays beim Anwenden des Arraynamens zurück. So für sizeof(str)
es gibt = 24 zurück, das heißt, die Größe des kompletten 2D-Char-Arrays besteht aus 24 Zeichen (6-Spalten* 4-Zeilen).
-
In diesem Deklarationstyp von str
ist char[4][6]
.
-
Ein weiterer interessanter Punkt ist str[i]
repräsentiert ein Array chats und sein Typ ist char[6]
. Und sizeof(str[0])
ist die Größe des kompletten Arrays = 6 (Zeilenlänge).
Zusätzliche Punkte:
-
In zweiter Erklärung str[i][j]
ist nicht konstant, und sein Inhalt kann sich ändern, z str[i][j] = 'A'
ist eine gültige Operation.
-
str[i]
ist der Name des char-Arrays vom Typ char[6]
ist eine Konstante und Zuweisung an str[i]
z.B str[i] = "newstring"
ist eine illegale Operation (infizieren, es wird ein Kompilierzeitfehler sein).
Noch ein wichtiger Unterschied zwischen zwei Deklarationen:
Im Erklärung-1: char *str[] = {"forgs", "do", "not", "die"};
Art der &str
ist char*(*)[4]
seine Adresse des Arrays von char-Zeigern.
Im Erklärung-2: char str[][6] = {"forgs", "do", "not", "die"};
Art der &str
ist char(*)[4][6]
seine Adresse eines 2-D-Char-Arrays mit 4 Zeilen und 6 Spalten.
Wenn man ähnliche Beschreibung für 1-D-Array lesen will: Was tut sizeof(&array)
Rückkehr?
In den meisten Fällen zerfällt ein Array-Name auf den Wert der Adresse seines ersten Elements, wobei der Typ mit einem Zeiger auf den Elementtyp identisch ist. Sie würden also einen nackten erwarten str
den Wert gleich haben &str[0]
mit Typ Zeiger auf Zeiger auf char
.
Dies ist jedoch nicht der Fall für sizeof
. In diesem Fall behält der Array-Name seinen Typ bei sizeof
was ein Array von 4 Zeigern wäre char
.
Der Rückgabetyp von sizeof
ist ein size_t
. Wenn Sie einen C99-Compiler haben, können Sie verwenden %zu
in der Formatzeichenfolge, um den von zurückgegebenen Wert zu drucken sizeof
.
Die beiden Zeiger sind unterschiedlich. str
ist ein array of char pointers
in Ihrem Beispiel ist ein (char*[4]
), und die str[0]
ist ein char pointer
.
Der Erste sizeof
gibt die Größe der vier char-Zeiger zurück, die enthält, und die zweite gibt die Größe von zurück char*
.
In meinen Tests sind die Ergebnisse:
sizeof(str[0]) = 4 // = sizeof(char*)
sizeof(str) = 16
= sizeof(str[0]) + sizeof(str[1]) + sizeof(str[2]) + sizeof(str[3])
= 4 * sizeof(char*)
= 4 * 4
= 16
Nein, überhaupt nicht richtig.
str
ist ein Array,str[0]
ein Array-Element.– Kerrek SB
10. Juli 2013 um 7:20 Uhr
Sind Sie sich der Werte 12 und 2 ganz sicher, die Sie angeblich erhalten? Das wäre eine ungewöhnliche Architektur. Übrigens,
%d
ist das falsche Format zum Drucken asize_t
(die Art vonsizeof(…)
). Eine Lösung wäre hier sicherzustellen, dass es keine Missverständnisse mit gibt(int)sizeof(str)
und(int)sizeof(str[0])
.– Pascal Cuoq
10. Juli 2013 um 7:24 Uhr
Die von Ihnen angegebene Ausgabe ist unrealistisch. Es kann nicht 12 und 2 sein.
– AnT steht zu Russland
10. Juli 2013 um 7:32 Uhr
Unabhängig von Ihrer Architektur sollte der erste Wert das 4-fache des zweiten sein. Auf einem 32-Bit-Rechner sollten Sie erhalten
16 4
auf einem 64-Bit-Gerät32 8
. Auf einem sehr alten oder auf einem eingebetteten System erhalten Sie möglicherweise sogar8 2
aber nie12 2
da das Array 4 Elemente der gleichen Größe enthält– glglgl
10. Juli 2013 um 7:33 Uhr
@PascalCuoq Selbst dann würde dies hier nicht gelten: Das Array sollte haben
n
mal so groß wie achar *
was auch immer das ist, mitn
die Anzahl der Array-Elemente ist.– glglgl
10. Juli 2013 um 7:37 Uhr