Was gibt sizeof(&array) zurück?

Lesezeit: 9 Minuten

Benutzeravatar von user1980750
Benutzer1980750

Nach der Frage: Wie kommt es, dass die Adresse eines Arrays gleich seinem Wert in C ist?

#include <stdio.h>
#define N 10    
char str2[N]={"Hello"};
int main(){
    printf("sizeof(str2): %d bytes\n", sizeof(str2));
    printf("sizeof(&str2): %d bytes\n", sizeof(&str2));
    return 0;
}

Ausgabe:

sizeof(str2): 10 bytes
sizeof(&str2): 4 bytes

ich weiß das str2 allein ist die Adresse des ersten Elements im Array str2. Und das wann str2 ist ein Argument von sizeof es gibt die Größe des gesamten Arrays str2 zurück.

Zusätzlich, &str2 ist auch die Adresse des ersten Elements in arr str2 aber von anderem Typ (char (*)[N] == Zeiger auf Array). Aber wie funktioniert &str2 Verhalten, wenn es ein Argument von ist sizeof?

  • “Ich weiß das str2 allein ist die Adresse des ersten Elements im Array str2” – Nun, das ist es nicht. Es wird in den meisten Kontexten in einen Zeiger auf sein erstes Element konvertiert, aber sizeof ist eine der Ausnahmen.

    – Daniel Fischer

    2. März 2013 um 19:01 Uhr

  • @DanielFischer also warum printf("%p %p",str2, str2+1); druckt die Adresse des ersten bzw. zweiten Elements?

    – Benutzer1980750

    2. März 2013 um 20:43 Uhr


  • @ user1980750 Denn das ist keine der Ausnahmen. Es sei denn, es ist der Operand von sizeof, _Alignof oder der Adressoperator &oder im Fall von Zeichenfolgenliteralen als Initialisierer für a char[], wird ein Ausdruck vom Typ Array in einen Zeiger auf das erste Element des Arrays konvertiert. Also rein die meisten Kontexten wird der Name eines Arrays zu einem Zeiger auf sein erstes Element ausgewertet, aber es ist etwas anderes (der Name eines Arrays).

    – Daniel Fischer

    2. März 2013 um 20:53 Uhr

  • @Daniel Fischer: _Alignof ist keine der Ausnahmen, da _Alignof kann nur auf einen Typnamen in Klammern angewendet werden, nicht auf einen Ausdruck. Das war ein Fehler in der N1570 Entwurf, korrigiert in der veröffentlichten Norm ISO C11. (Wie für warum _Alignof kann nicht auf einen Ausdruck angewendet werden, das ist eine andere Frage.)

    – Keith Thompson

    29. August 2013 um 15:03 Uhr

  • @KeithThompson Inzwischen weiß ich das. Ich glaube, du warst es, der es mir gesagt hat, aber es hätte auch jemand anderes sein können. Aber trotzdem danke, auch wenn es ein wiederholter Dank ist.

    – Daniel Fischer

    29. August 2013 um 15:11 Uhr

Benutzeravatar von Grijesh Chauhan
Grijesh Chauhan

Unterschied zwischen &str und strWenn str wird als deklariert char str[10]?

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

Also, nach Ihrer Erklärung, sizeof(str2) gibt die vollständige Arraygröße an, die 10 Byte beträgt (weil N als 10 definiert ist und die Zeichengröße 1 Byte beträgt).
Während im Ausdruck sizeof(&str2), &str2 ist eine Adresse eines Arrays und die Größe dieser Adresse beträgt 4 Bytes auf Ihrem System. (Adressgröße kann 8 Bytes in einigen Systemen zB 64-Bit sein).

Zusätzlich, &str2 ist auch die Adresse des ersten Elements in arr str2?

Neinwertmäßig beides &str2 und str sind gleich, aber semantisch sind beide verschieden. Eines ist eine Adresse eines Arrays von 10 Zeichen, während das andere eine Adresse eines Zeichens ist.

Einer Unterschied, den Sie in Ihrem eigenen Beispiel zwischen ihnen gesehen haben, ist (@ouah erklärte dies in einer Antwort).

  • Art der str ist char[10]
  • Art der &str ist char(*)[10]

Zweite:
Wenn Sie einem Diagramm folgen, können Sie den anderen Unterschied erkennen.

for declaration: 
#define N 10
char str2[N] = {"Hello"};

str2 Array in memory is something like:
----------------------------------------

str
+----+----+----+----+----+----+----+----+----+----++----+
|'H' |'e' |'l' |'l' |'o' |'\0'|'\0'|'\0'|'\0'|'\0'|| '@'|
+----+----+----+----+----+----+----+----+----+----++----+
 201   202  203 204  205   206  207  208  209  210   211
▲ ▲     ▲                                             ▲
| |     |                                             |
|(str2) (str2 + 1)                                    | 
|                                                     |
|-----------------------------------------------------|
|201                                                  | 
|                                                     |
|                                                     |
(&str2) = 201                           (&str2 + 1) = 211


* assuming str address start from 201
* str[N] is 10 char long 201-210, partially initialized
* at uninitialized position, str2[i] = '\0'
* location 211 is unallocated, having garbage value,
  access to this location is illegal-Undefined Behavior

Für das obige Diagramm können Sie Code schreiben wie:

#include <stdio.h>
#define N 10    
int main(){
   char str2[N]={"Hello"};
  
   printf("\n %p, %p\n",str2, str2+1);
   printf("\n %p, %p\n",(&str2), (&str2+1));
}  

Ausgabe:

 0xbf67e142, 0xbf67e143

 0xbf67e142, 0xbf67e14c

EIN Link für Codepad:

Beachten Sie, dass sich die Ausgangsadressen in der ersten Zeile um ein Byte unterscheiden, in der zweiten jedoch 10 Bytes, da es sich um die Arrays Zeiger (wie im Diagramm oben gezeigt).

Gemäß den Regeln der Zeigerarithmetik zeigt eine Zeigervariable, wenn Sie 1 addieren, auf das nächste Element ihres eigenen Typs. Das ist der Grund für die 10 Byte Differenz, weil &str2 ist eine Adresse, die auf ein Array zeigt.

Dritte Unterschied:

Indem ich es mache *str2 Sie können auf das erste Element zugreifen. Wohingegen *(&str2) gibt Ihnen nicht das erste Element, sondern die Adresse des ersten Elements.

Hier hilft ein Beispiel:

#include <stdio.h>
#define N 10    
int main(){
   char str2[N]={"Hello"};
   printf("\n%p %c, %p %c\n",str2, *(str2), *(&str2), **(&str2));
}  

Ausgang:

0xbf587046 H, 0xbf587046 H

Codepad-Link

Im Ausgang

str2 gives  0xbf587046 
*(str2)     H 
*(&str2)    0xbf587046 
**(&str2)   H 

Das bedeutet *(&str2) == str2 und Wert ist Adresse. Und daher *(str2) = **(&str2) Werte ist H.

Bearbeiten: Oben habe ich den Unterschied zwischen gezeigt &str und str wo str ist ein Array vom Typ char[10].

Unterschied zwischen char *str und char str[] und wie beide im Gedächtnis gespeichert werden

Angenommen, wir haben zwei Deklarationen wie unten:

char *str1 = "hello";   
char str2[] = "hello";  

In den obigen Erklärungen str1 ist ein Hinweis auf chardas auf ein konstantes String-Literal zeigt (indem die Adresse des ersten Zeichens gehalten wird h in "hello" Schnur).

Ein String in C ist of char[N] (Array) Typ, deshalb sizeof("hello") gibt 6 weil "hello" string ist ein 6 Zeichen langes Array (enthalten \0 nul, Zeichenfolgenterminierung, Art von hallo ist char[6]).

In Erinnerung an Ihre "hello" Zeichenfolge wird wie folgt gespeichert:

 str1         23   24   25   26   27   28
+----+      +----+----+----+----+----+----+
| 23 |      | h  | e  |  l | l  | o  | \0 |    
+----+      +----+----+----+----+----+----+
   +-----------▲

here the address of the hello string is the first address = 23.  
str1: is a pointer capable of storing an address. 
"hello" consists of 6 chars

char* str1 = "hello"; speichert im Grunde eine Adresse einer Zeichenfolge hallo in einer Zeigervariablen str1 wie ich in der obigen Abbildung zeige.

Hinweis: Wenn Sie möchten, können Sie ändern str1 um auf eine andere Zeichenfolge zu zeigen. Aber man kann nicht modifizieren hello Schnur. zum Beispiel ist folgender Code gültig:

 char* str1 = "hello";  // str1 points to hello  str1-->"hello"
 str1 = "world";  //Now, str1 points to world  str1-->"world"

Jetzt str1 weist auf eine andere Konstanten-String-Welt hin.

 str1         93   94   95   96   97   98 
+----+      +----+----+----+----+----+----+
| 93 |      | w  | o  |  r | l  | d  | \0 |    
+----+      +----+----+----+----+----+----+
   +-----------▲

here address of world string is first address = 93.  
str1: value change to point string world. 

Wichtig zu beachten: str1 zeigt auf konstante Zeichenfolgen, daher können Sie die Zeichenfolge nicht ändern, indem Sie beispielsweise auf den Speicherort zugreifen/indizieren str1[i] = 'A'; wird illegal sein, weil Sie es sind Schreiben auf Nur-Lese-Speicher und das Verhalten davon ist zur Laufzeit undefiniert (obwohl kein Kompilierungsfehler, da es syntaktisch korrekt ist).

Nochmal, weil str1 ist ein Zeiger sizeof(str1) wird 4 auf derselben Maschine geben.

Mein folgender Code und seine Ausführung:

#include <stdio.h>
int main(){
   char* str1="Hello";
   printf("\nstr1: %s, address: %p, sizeof(str1): %u", str1, str1, sizeof(str1));
   str1 = "world";
   printf("\nstr1: %s, address: %p, sizeof(str1): %u", str1, str1, sizeof(str1));
   return 1;
}  

Ausgabe:

str1: Hello, address: 0x80485e8, sizeof(str1): 4
str1: world, address: 0x8048619, sizeof(str1): 4

Codepad-Link

Um also einen neuen String zuzuweisen, weise ich einfach eine Adresse eines neuen Strings zu. Aber ich kann nicht anrufen strcpy() das versucht, auf einen Nur-Lese-Speicherort zu schreiben, und das ist illegal.

In der zweiten Erklärung char str2[] = "hello";, str2[] ist ein \0 abgeschlossenes Array von Zeichen (oder Zeichenfolgen), aber KEIN Zeiger. Beachten Sie, dass in dieser Deklaration die Größe nicht angegeben ist Standard Größesehen wir, dass die Größe der konstanten Zeichenfolge „Hallo“ 6 beträgt. Typ von str2 ist char[6].

Wenn wir es tun char str2[] = "hello"; Ein Array von char wird erstellt und die Zeichenfolge hello wird in dieses Array kopiert. So str2 ist nicht einfach ein Zeiger, sondern ein Array, das einen vollständigen String speichert.

Konzeptionell ist es wie

       str2:
       103  104  105  106  107  108
      +----+----+----+----+----+----+
      | h  | e  |  l | l  | o  | \0 |    
      +----+----+----+----+----+----+

In diesem Fall sind Sie in letzter Zeit in Ihrem Code nicht erlaubt zu tun str2[] = "world"; oder str2 = "world"wird es ein Kompilierzeitfehler sein.

Beispielcode:

#include<stdio.h>
int main(){
 char str2[] = "hello";
 str2[] = "world";
 str2 = "world"; 
 return 1; 
}

Kompilierungsfehler:

In function 'main':
Line 4: error: expected expression before ']' token
Line 5: error: incompatible types in assignment

Codescape-Link

Wo dieses Array str2 ist keine Konstante, wir können seinen Inhalt zum Beispiel dadurch ändern str2[2] = 'A' ist vollkommen gültig. Wir können auch strcpy aufrufen, um den Inhalt zu ändern (und der Adressraum ändert sich nicht).

       strcpy(str2, "world");

       str2:
       103  104  105  106  107  108
      +----+----+----+----+----+----+
      | w  | o  |  r | l  | d  | \0 |    
      +----+----+----+----+----+----+

      Note that when "world" is copied into a same memory space, the addresses of both "world" and "hello"
      string are the same.  

Codebeispiel:

#include<stdio.h>
int main(){
 char str2[] = "hello";
 printf("\nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));
 str2[2] = 'A';
 printf("\nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));
 strcpy(str2, "world");
 printf("\nstr2: %s, address: %p, sizeof(str2): %u", str2, str2, sizeof(str2));
 return 1; 
}

Ausgabe:

str2: hello, address: 0xbf58d056, sizeof(str2): 6
str2: heAlo, address: 0xbf58d056, sizeof(str2): 6
str2: world, address: 0xbf58d056, sizeof(str2): 6

Codepad-Link

Hinweis: Zeichenfolgenwerte sind im selben Adressraum unterschiedlich. sizeof(str2) = 6 perfekt verstanden aus älterer Antwort, die die Größe des Arrays in Bytes ist.

Um eine ähnliche Beschreibung zu zweidimensionalen Arrays zu lesen, lesen Sie: Unterschied zwischen char* str[] und char str[][] und wie speichert beides im Gedächtnis?

&str2 ist ein Zeiger. Sie sehen also nur die Größe eines Zeigers auf Ihrer Plattform.

  • Es ist nicht Notwendig der Fall, dass alle Zeigertypen die gleiche Größe haben, obwohl dies für die meisten Implementierungen gilt.

    – Keith Thompson

    29. August 2013 um 15:04 Uhr

str2 ist vom Typ char [10] (dh Array 10 ofZeichen`)

&str2 ist vom Typ char (*)[10] (dh Zeiger auf ein Array 10 von char).

So sizeof (&str2) liefert die Größe eines Objekts vom Typ Zeiger char (*)[10]

Benutzeravatar von VimNing
VimNing

Wenn Sie einfach die Variable verwenden arr (wie beschrieben char arr[10]), es immer zerfällt zu einem konstanten Zeiger char *const arr zeigt auf das erste Element. Während &arr ergibt einen Zeiger char (*)[10] das beinhaltet die Größe von arrich G 10.

1386480cookie-checkWas gibt sizeof(&array) zurück?

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

Privacy policy