Was ist der Unterschied zwischen char array und char pointer in C?
C99 N1256 Entwurf
Es gibt zwei verschiedene Verwendungen von Zeichenkettenliteralen:
Initialisieren char[]:
char c[] = "abc";
Dies ist "mehr Magie" und wird unter 6.7.8 / 14 "Initialisierung" beschrieben:
Ein Array vom Zeichentyp kann durch ein Zeichenfolgenliteral initialisiert werden, das optional in geschweiften Klammern eingeschlossen ist. Aufeinanderfolgende Zeichen des Zeichenfolgenliteral (einschließlich des abschließenden Nullzeichens, wenn Platz vorhanden ist oder wenn das Array eine unbekannte Größe hat) initialisieren die Elemente des Arrays.
Dies ist also nur eine Abkürzung für:
char c[] = {'a', 'b', 'c', '\0'};
cKann wie jedes andere reguläre Array geändert werden.
Überall sonst: es erzeugt ein:
Also, wenn Sie schreiben:
char *c = "abc";
Dies ist ähnlich wie:
/* __unnamed is magic because modifying it gives UB. */
static char __unnamed[] = "abc";
char *c = __unnamed;
Beachten Sie die implizite Besetzung von char[]bis char *, die immer legal ist.
Wenn Sie dann ändern c[0], ändern Sie auch __unnamed, was UB ist.
Dies ist unter 6.4.5 "String-Literale" dokumentiert:
5 In der Übersetzungsphase 7 wird an jede Multibyte-Zeichenfolge, die sich aus einem String-Literal oder Literalen ergibt, ein Byte oder ein Code mit dem Wert Null angehängt. Die Multibyte-Zeichenfolge wird dann verwendet, um ein Array mit statischer Speicherdauer und -länge zu initialisieren, das gerade ausreicht, um die Folge aufzunehmen. Bei Zeichenkettenliteralen haben die Array-Elemente den Typ char und werden mit den einzelnen Bytes der Multibyte-Zeichenfolge [...] initialisiert.
6 Es ist nicht spezifiziert, ob diese Arrays unterschiedlich sind, vorausgesetzt, ihre Elemente haben die entsprechenden Werte. Wenn das Programm versucht, ein solches Array zu ändern, ist das Verhalten undefiniert.
6.7.8 / 32 "Initialisierung" gibt ein direktes Beispiel:
BEISPIEL 8: Die Erklärung
char s[] = "abc", t[3] = "abc";
definiert "einfache" char-Array-Objekte sundt deren Elemente mit Zeichenfolge Literale initialisiert.
Diese Erklärung ist identisch mit
char s[] = { 'a', 'b', 'c', '\0' },
t[] = { 'a', 'b', 'c' };
Der Inhalt der Arrays kann geändert werden. Auf der anderen Seite die Erklärung
char *p = "abc";
definiert pmit dem Typ "Zeiger auf Zeichen" und initialisiert es so, dass es auf ein Objekt mit dem Typ "Array von Zeichen" mit der Länge 4 zeigt, dessen Elemente mit einem Zeichenfolgenliteral initialisiert werden. Wenn versucht wird, pden Inhalt des Arrays zu ändern, ist das Verhalten undefiniert.
GCC 4.8 x86-64 ELF-Implementierung
Programm:
#include <stdio.h>
int main(void) {
char *s = "abc";
printf("%s\n", s);
return 0;
}
Kompilieren und dekompilieren:
gcc -ggdb -std=c99 -c main.c
objdump -Sr main.o
Die Ausgabe enthält:
char *s = "abc";
8: 48 c7 45 f8 00 00 00 movq $0x0,-0x8(%rbp)
f: 00
c: R_X86_64_32S .rodata
Fazit: GCC speichert char*es in .rodataAbschnitt, nicht in .text.
Wenn wir dasselbe tun für char[]:
char s[] = "abc";
wir erhalten:
17: c7 45 f0 61 62 63 00 movl $0x636261,-0x10(%rbp)
so wird es im Stapel gespeichert (relativ zu %rbp).
Beachten Sie jedoch , dass der Standard Linker - Skript setzt .rodataund .textim gleichen Segment, das auszuführen hat , aber keine Schreibrechte. Dies kann beobachtet werden mit:
readelf -l a.out
was beinhaltet:
Section to Segment mapping:
Segment Sections...
02 .text .rodata
char p[3] = "hello";Die Initialisierungszeichenfolge ist zu lang für die Größe des von Ihnen deklarierten Arrays. Tippfehler?