Unterschied zwischen &str
und str
Wenn 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 char
das 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?
“Ich weiß das
str2
allein ist die Adresse des ersten Elements im Arraystr2
” – Nun, das ist es nicht. Es wird in den meisten Kontexten in einen Zeiger auf sein erstes Element konvertiert, abersizeof
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 achar[]
, 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