Когда использовать char a[] над char p* и наоборот?


В последнее время я изучаю все о языке Си, и меня смущает, что Когда использовать

char a[];

Над

char *p;

Когда речь заходит о манипуляциях со строками. Например, я могу назначить строку им обоим следующим образом:

char a[] = "Hello World!";
char *p = "Hello World!";

И просматривать / получать доступ к ним обоим, как:

printf("%sn", a);
printf("%sn", p);

И манипулировать ими обоими, как:

printf("%cn", &a[6]);
printf("%cn", &p[6]);

Итак, что я упускаю?

2 4

2 ответа:

char a[] = "Hello World!";

Это выделяет модифицируемый массив, достаточно большой, чтобы содержать строковый литерал (включая завершающий символ NUL). Затем он инициализирует массив содержимым строкового литерала. Если это локальная переменная, то это фактически означает, что она делает memcpy во время выполнения, каждый раз, когда создается локальная переменная.

Используйте это, когда вам нужно изменить строку, но не нужно делать ее больше.

Также, если у вас есть char *ap = a;, Когда a выходит из области ap становится болтающимся указатель. Или, то же самое, вы не можете сделать return a;, Когда a локально для этой функции, потому что возвращаемое значение будет висячим указателем на Теперь уничтоженные локальные переменные этой функции.

Обратите внимание, что использование именно этого встречается редко. Обычно вам не нужен массив с содержимым из строкового литерала. Гораздо чаще встречается что-то вроде:

char buf[100]; // contents are undefined
snprintf(buf, sizeof buf, "%s/%s.%d", pathString, nameString, counter);

char *p = "Hello World!";

Это определяет указатель и инициализирует его для указания на строковый литерал. Обратите внимание, что строковые литералы (обычно) не доступно для записи, поэтому вы действительно должны иметь это вместо:

const char *p = "Hello World!";

Используйте это, когда вам нужен указатель на немодифицируемую строку.

В отличие от a выше, если у вас есть const char *p2 = p; или есть return p;, это нормально, потому что указатель указывает на строковый литерал в постоянных данных программы и действителен для всего выполнения программы.


Сами строковые литералы, текст с двойными кавычками, фактические байты, составляющие строки, создаются в время компиляции и обычно помещается с другими постоянными данными в приложении. И тогда строковый литерал в коде конкретно означает адрес этого постоянного blob-объекта данных.

char * строки доступны только для чтения. Они не могут быть изменены, в то время как строки char[] могут быть изменены.

char *str = "hello"; str[0] = 't'; // This is an illegal operation

Тогда как

char str[] = "hello"; str[0] = 't'; // Legal, string becomes tello