Biorąc pod uwagę deklaracje
char *s0 = "hello world";
char s1[] = "hello world";
przyjmij następującą hipotetyczną mapę pamięci:
0x01 0x02 0x03 0x04
0x00008000: „h” „e” „l” „l”
0x00008004: „o” „w” „o”
0x00008008: „r” „l” „d” 0x00
...
s0: 0x00010000: 0x00 0x00 0x80 0x00
s1: 0x00010004: „h” „e” „l” „l”
0x00010008: „o” „w” „o”
0x0001000C: „r” „l” „d” 0x00
Dosłowny ciąg znaków "hello world"
to 12-elementowa tablica char
( const char
w języku C ++) ze statycznym czasem przechowywania, co oznacza, że pamięć jest przydzielana podczas uruchamiania programu i pozostaje przydzielona do czasu zakończenia programu. Próba modyfikacji zawartości literału łańcuchowego wywołuje niezdefiniowane zachowanie.
Linia
char *s0 = "hello world";
definiuje s0
jako wskaźnik char
z automatycznym czasem przechowywania (co oznacza, że zmienna s0
istnieje tylko dla zakresu, w którym została zadeklarowana) i kopiuje do niej adres literału łańcucha ( 0x00008000
w tym przykładzie). Należy zauważyć, że ponieważ s0
wskazuje na ciągiem znaków, nie powinno być wykorzystywane jako argument do dowolnej funkcji, które starają się je modyfikować (np strtok()
, strcat()
, strcpy()
itd.)
Linia
char s1[] = "hello world";
definiuje s1
jako 12-elementową tablicę char
(długość jest pobierana z literału łańcucha) z automatycznym czasem przechowywania i kopiuje zawartość literału do tablicy. Jak widać z mapy pamięci, mamy dwie kopie ciągu "hello world"
; Różnica polega na tym, że możesz zmodyfikować ciąg znaków zawarty w s1
.
s0
i s1
są wymienne w większości kontekstów; oto wyjątki:
sizeof s0 == sizeof (char*)
sizeof s1 == 12
type of &s0 == char **
type of &s1 == char (*)[12] // pointer to a 12-element array of char
Możesz ponownie przypisać zmienną, s0
aby wskazywała inny literał łańcuchowy lub inną zmienną. Nie można ponownie przypisać zmiennej, s1
aby wskazywała inną tablicę.