Was bedeutet der ‘Array-Name’ im Falle eines Arrays von Zeichenzeigern?

Lesezeit: 11 Minuten

Benutzer-Avatar
Nithish Streben nach Glück

In meinem Code:

 char *str[] = {"forgs", "do", "not", "die"};
 printf("%d %d", sizeof(str), sizeof(str[0]));  

Ich bekomme die Ausgabe als 12 2also meine zweifel sind:

  1. Warum gibt es einen Unterschied?
  2. Beide str und str[0] sind Zeichenzeiger, richtig?

  • 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 a size_t (die Art von sizeof(…)). 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 4auf einem 64-Bit-Gerät 32 8. Auf einem sehr alten oder auf einem eingebetteten System erhalten Sie möglicherweise sogar 8 2aber nie 12 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 a char *was auch immer das ist, mit n die Anzahl der Array-Elemente ist.

    – glglgl

    10. Juli 2013 um 7:37 Uhr


Benutzer-Avatar
Grijesh Chauhan

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?

  • … das Ergebnis ist die Größe des gesamten Arrays und nicht die Größe des Zeigers, der durch den Array-Bezeichner dargestellt wird. Wenn der Bezeichner ein Array darstellt, stellt er keinen Zeiger dar.

    – PP

    18. Juli 2013 um 6:18 Uhr

  • Ihr Zitat sagt “… eher die Größe des durch Array dargestellten Zeigers”. Ein Array-Name stellt keinen Zeiger dar. Es kann bequem in einen Zeiger zerfallen, aber das macht es nicht zu einem Zeiger.

    – PP

    18. Juli 2013 um 6:26 Uhr

  • Sie müssen es nicht wirklich selbst zitieren und erklären. Wenn Sie einen zitieren möchten, sehen Sie sich 6.5.3.4 in C11 an, in dem es heißt ...When applied to an operand that has array type, the result is the total number of bytes in the array und kann auch die Definition von sizeof im selben Abschnitt sein.

    – PP

    18. Juli 2013 um 7:05 Uhr

  • Hier ein Tippfehler. Die Adressen wären (Dezimalwerte) 343, 351, 359, 367 Anstatt von 343, 344, 345, 346. für 32-Bit-Architektur

    – noufal

    4. September 2013 um 11:41 Uhr

  • @noufal Danke, korrigiert den Tippfehler, den du bemerkt hast, aber ich gehe von 4 Byte aus char* laut codepade habe ich den code verlinkt

    – Grijesh Chauhan

    4. September 2013 um 19:14 Uhr

Benutzer-Avatar
jxh

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 sizeofwas 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.

  • Aber das erklärt nicht die 12 2… trotzdem +1

    – glglgl

    10. Juli 2013 um 7:35 Uhr

  • @glglgl Die „12 2“ erklärt sich wohl durch size_t 64-Bit ist und bei der Übergabe undefiniertes Verhalten aufruft printf mit einer %d Format, gemäß meinem Kommentar.

    – Pascal Cuoq

    10. Juli 2013 um 7:37 Uhr

  • @PascalCuoq Das könnte der Fall sein, aber dann würde ich lieber a erwarten 0 irgendwo, egal ob little oder big endian… Aber man weiß ja nie, was die eine oder andere Plattform für komische Sachen macht.

    – glglgl

    10. Juli 2013 um 7:39 Uhr

  • Wenn Ihre Implementierung dies unterstützt, verwenden Sie "%zu" drucken a size_t Wert. Wenn dies nicht der Fall ist (Microsoft wahrscheinlich nicht), verwenden Sie "%lu" und wandle den Wert in um unsigned long. Oder, wenn Sie faul sind und die Werte bekanntermaßen klein sind, verwenden Sie "%d" und umwandeln in int.

    – Keith Thompson

    15. Juli 2013 um 20:16 Uhr

  • Die unkonventionellen Werte können auch darauf zurückzuführen sein, dass kein geeigneter Prototyp für enthalten ist printf im Programm, und so wendete das System die Variablenargument-Makros auf etwas Zufälliges an.

    – jxh

    22. Mai 2018 um 5:39 Uhr

Benutzer-Avatar
Manas

Es ist 16 4 auf meinem Computer, und ich kann dies erklären: str ist ein Array von char*Also sizeof(str)==sizeof(char*)*4

Ich weiß nicht, warum Sie bekommen 12 2 obwohl.

Benutzer-Avatar
superarsch

Die beiden Zeiger sind unterschiedlich. str ist ein array of char pointersin 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

1344680cookie-checkWas bedeutet der ‘Array-Name’ im Falle eines Arrays von Zeichenzeigern?

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

Privacy policy