?
кажется опечаткой, это не семантически допустимо. Таким образом, ответ предполагает, что ?
является опечаткой, и объясняет, что, вероятно, интервьюер действительно хотел спросить.
Оба явно различны, для начала:
- Первый создает указатель.
- Второй создает массив.
Читайте дальше для более подробного объяснения:
Версия Array:
char a[] = "string";
Создает массив, достаточно большой для размещения строкового литерала "string", включая его терминатор NULL
. Массив string
инициализируется строковым литералом "строка". Массив можно изменить позже . Кроме того, размер массива известен даже во время компиляции, поэтому для определения его размера можно использовать оператор sizeof
.
Версия указателя:
char *p = "string";
Создает указатель для указания строкового литерала "строка". Это быстрее, чем версия массива, , но строка, указанная указателем, не должна изменяться , потому что она находится в памяти, доступной только для чтения. Изменение такого строкового литерала приводит к неопределенному поведению .
На самом деле C ++ 03 не поддерживает [Ref 1] использование строкового литерала без ключевого слова const
. Таким образом, декларация должна быть:
const char *p = "string";
Кроме того, необходимо использовать функцию strlen()
, а не sizeof
, чтобы найти размер строки , поскольку оператор sizeof
просто даст вам размер переменной-указателя. 1049 *
Какая версия лучше, и какую мне использовать?
Зависит от использования.
- Если вам не нужно вносить какие-либо изменения в строку, используйте версию указателя.
- Если вы намереваетесь изменить данные, используйте версию массива.
Примечание: Это не C ++, но это специфично для C.
Обратите внимание, что использование строкового литерала без ключевого слова const
вполне допустимо в C.
Однако изменение строкового литерала все еще остается неопределенным поведением в C [Ref 2] .
Это поднимает интересный вопрос,
В чем разница между char * и const char * при использовании строковых литералов в C?
Для фанатов Standerdese:
[Ссылка 1] C ++ 03 Стандарт: § 4.2 / 2
Строковый литерал (2.13.4), который не является широким строковым литералом, может быть преобразован в значение типа «указатель на символ»; широкий строковый литерал может быть преобразован в значение типа «указатель на wchar_t». В любом случае результатом является указатель на первый элемент массива. Это преобразование рассматривается только при наличии явного соответствующего целевого типа указателя, а не при общей необходимости преобразования из lvalue в rvalue. [ Примечание: это преобразование устарело . См. Приложение D.] В целях ранжирования по разрешению перегрузки (13.3.3.1.1) это преобразование считается преобразованием массива в указатель, за которым следует преобразование квалификации (4.4). [Пример: «abc» преобразуется в «указатель на const char» как преобразование массива в указатель, а затем в «указатель на char» как преобразование квалификации. ]
C ++ 11 просто удаляет приведенную выше цитату, которая подразумевает, что это недопустимый код в C ++ 11.
[Ref 2] Стандарт C99 6.4.5 / 5 "Строковые литералы - семантика":
В переводеНа этапе 7 к каждой многобайтовой символьной последовательности добавляется байт или код нулевого значения, которые являются результатом строкового литерала или литералов.Последовательность многобайтовых символов затем используется для инициализации массива статической длительности хранения и длины, достаточной только для того, чтобы содержать последовательность.Для строковых литералов символов элементы массива имеют тип char и инициализируются отдельными байтами многобайтовой последовательности символов;для широких строковых литералов элементы массива имеют тип wchar_t и инициализируются последовательностью широких символов ...
Не определено, различаются ли эти массивы при условии, что их элементы имеют соответствующие значения. Если программа пытается изменить такой массив, поведение не определено.