З огляду на декларації
char *s0 = "hello world";
char s1[] = "hello world";
припустимо наступну гіпотетичну карту пам'яті:
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
Літеральний рядок "hello world"
- це 12-елементний масив char
( const char
у C ++) зі статичною тривалістю зберігання, тобто пам'ять для нього виділяється при запуску програми і залишається виділеною до завершення програми. Спроба змінити вміст рядкового літералу викликає невизначене поведінку.
Лінія
char *s0 = "hello world";
визначає s0
як покажчик на char
тривалість автоматичного зберігання (означає, що змінна s0
існує лише для області, в якій вона оголошена) і копіює адресу рядкового літералу ( 0x00008000
у цьому прикладі) до нього. Слід зазначити , що , оскільки s0
вказує на рядок литерала, вона не повинна бути використана в якості аргументу для будь-якої функції , яка буде намагатися змінити його (наприклад, strtok()
, strcat()
, strcpy()
і т.д.).
Лінія
char s1[] = "hello world";
визначає s1
як 12-елементний масив char
(довжина взята з рядкового літералу) з тривалістю автоматичного зберігання та копіює вміст літералу в масив. Як видно з карти пам'яті, у нас є дві копії рядка "hello world"
; Різниця полягає в тому, що ви можете змінити рядок, що міститься в s1
.
s0
і s1
є взаємозамінними у більшості контекстів; ось винятки:
sizeof s0 == sizeof (char*)
sizeof s1 == 12
type of &s0 == char **
type of &s1 == char (*)[12] // pointer to a 12-element array of char
Ви можете перепризначити змінну s0
для вказівки на інший рядковий літерал або іншу змінну. Ви не можете перепризначити змінну s1
для вказівки на інший масив.