2010-10-29 2 views
9

Выполняют ли эти две строки кода одинаковые результаты? Если бы я имел эти строки в функции, это строка, хранящаяся в стеке в обоих случаях? Есть ли веская причина, почему я должен использовать один над другим, кроме того, что вам не нужно объявлять нулевой терминатор в первой строке кода?В C, можно ли инициализировать строку в объявлении указателя так же, как я могу инициализировать строку в объявлении массива?

char s[] = "string"; 
char* s = "string\0"; 
+7

Для получения информации вам не нужно использовать \ 0 во втором примере. При использовании двойных кавычек \ 0 всегда вставляется в массив. – RMAAlmeida

+0

И только для словаря то, о чем вы говорите, это не назначения, а декларации с инициализаторами. Они подчиняются различным правилам. E.g ваш первый оператор не будет разрешен как назначение, вы не можете назначить массивы. –

+0

Возможный дубликат [C: различия между указателем и массивом] (http://stackoverflow.com/questions/1335786/c-differences-between-pointer-and-array) –

ответ

23

Нет, эти две линии не достигают такого же результата.

char s[] = "string" приводит к модифицируемому массиву из 7 байтов, который изначально заполняется содержимым 's' 't' 'r' 'i' 'n' 'g' '\0' (все они скопированы во время выполнения из строкового литерала).

char *s = "string" приводит к указателю на некоторый только для чтения память, содержащая строку «буква».

Если вы хотите изменить содержимое своей строки, то первым является единственный способ пойти. Если вам нужен только доступ только для чтения к строке, то второй будет немного быстрее, потому что строка не должна быть скопирована.


В обоих случаях нет необходимости указывать нулевой ограничитель в строковом литерале. Компилятор будет заботиться о том, что для вас, когда он сталкивается с закрытием»

+5

Кроме того, второй разрешен только для ужасного наследия причины. Вы должны использовать 'const char * s =" string ";' –

+0

@Steve: для C++ я бы полностью согласился с вами. Для C я склонен дать немного больше возможностей, потому что на практике слишком много способов, которыми 'const' попадает на ваш путь. (Это также известно как const-poisoning) –

+2

Если я использую изворотливые библиотеки, я согласен с вами (иногда). Если код находится под моим контролем, я исправляю его так, чтобы 'const' не мешал мне. Альтернативой является получение копий строк, которые должны передаваться как неконстантные параметры для изворотливых API. Иногда это возможно, например, если передаваемая строка является литералом, определенным рядом с вызовом или глобальным, тогда просто используйте первый из двух указанных выше вариантов. В других случаях это PITA, и в этом случае вы можете либо взять удар strdup, либо отбросить 'const' (что« небезопасно », но затем вы уже используете« небезопасный »API). –

2

Разница между этими двумя:.

char a[] = "string"; 
char* b = "string"; 

является то, что на самом деле представляет собой статический массив в стеке, в то время как б является указателем константа. вы можете изменить содержание, но не б.

1

в дополнение к другим ответам я попытаюсь объяснить, почему вы не можете изменить переменную *s позже потока программы.

Концептуально, когда программа загружается в память имеет 3 зоны (сегменты):

  • сегмент коды: текст вашей программы хранится здесь (это только для чтения области)
  • сегмента данных: содержит какое-либо глобальные или статические переменные, которые имеют предварительно заданное значение и может быть изменено
  • сегмент стека: здесь загружаются функции по мере их вызова. Набор значений (стоп-фрейм), вставляемый в стек для каждого вызова функции, который содержит адрес возврата от функции и локальных переменных.

В вашем случае переменная s[] является локальной переменной (массив), в функции main(), которая инициализируется со значением "string". Таким образом, он сохраняется в стеке и может быть изменен.

Переменная *s - указатель, указывающий на адрес "string\0", постоянный, расположенный в сегменте кода. Будучи областью только для чтения, вы не можете изменять ее содержимое.

Смежные вопросы