что вы подразумеваете под " константным строковым литералом" в C (не C ++)
gbulmer
1
... имя char * может указывать на постоянный строковый литерал
Iceman
константа в «константе строкового литерала» является избыточной, поскольку все строковые литералы в теории являются постоянными сущностями. Это содержимое переменной, которое можно сделать постоянным или изменяемым. Объявление «const» просто выдаст ошибку времени компиляции, если вы попытаетесь изменить содержимое символа, на который указывает «имя»
Cupcake
Просто: имя "char * name" - это указатель на char, то есть оба можно изменить здесь. "const char * name" name это указатель на const char, т.е. указатель может меняться, но не char.
АКД
Прочитайте эти вещи справа налево.
Цзяпэн Чжан
Ответы:
406
char*является изменяемым указатель на изменяемый символ / строка.
const char*является изменяемым указатель на непреложный символ / строка. Вы не можете изменить содержимое местоположения, на которое указывает указатель. Кроме того, компиляторы обязаны выдавать сообщения об ошибках, когда вы пытаетесь это сделать. По той же причине преобразование из const char *в char*не рекомендуется.
char* constявляется неизменным указателем (он не может указывать на любое другое местоположение), но содержимое местоположения, на которое он указывает, является изменяемым .
const char* constявляется непреложным указатель на непреложный символ / строка.
Путаница может быть устранена с использованием переменной после операторов, упомянутых выше, и путем ссылки на эту переменную.
ankit.karwasra
3
@ ankit.karwasra, Вы пропустили еще один:char const *
Pacerier
Я предлагаю два варианта с изменяемым символом / строкой, которые очень опасны, так как вы можете создать память ошибок сегментации, а если вы действительно умны, вы можете взломать компьютер. Вот почему я думаю, что компиляторы всегда показывали предупреждения в этих реализациях
Даниэль Н.
1
Не будет ли мутация char *давать ошибку сегментации во время работы?
Divyanshu Maithani
1
Поэтому я использую, constесли я хочу, чтобы компилятор выдавал ошибку, если я забыл и изменил данные по ошибке, верно?
Бухгалтер م
43
char*name
Вы можете изменить символ, на который nameуказывает, а также символ, на который он указывает.
constchar* name
Вы можете изменить символ, на который nameуказывает, но вы не можете изменить символ, на который он указывает. Исправление: Вы можете изменить указатель, но не символ, на который nameуказывает ( https://msdn.microsoft.com/en-us/library/vstudio/whkd4k6a(v=vs.100).aspx , см. «Примеры» ). В этом случае constуказатель относится к charзвездочке, а не к ней.
Согласно странице MSDN и http://en.cppreference.com/w/cpp/language/declarations , constbefore *является частью последовательности спецификатора decl, а constafter *является частью декларатора.
За последовательностью спецификатора объявления могут следовать несколько объявлений, поэтому const char * c1, c2объявляется c1как const char *и c2как const char.
РЕДАКТИРОВАТЬ:
Судя по комментариям, ваш вопрос, похоже, касается разницы между двумя объявлениями, когда указатель указывает на строковый литерал.
В этом случае вы не должны изменять символ, на который nameуказывает, так как это может привести к неопределенному поведению . Строковые литералы могут быть размещены в областях памяти, доступных только для чтения (реализация определяется), и пользовательская программа не должна изменять их в любом случае. Любая попытка сделать это приводит к неопределенному поведению.
Таким образом, единственное отличие в этом случае (при использовании строковых литералов) заключается в том, что второе объявление дает вам небольшое преимущество. Компиляторы обычно выдают предупреждение в случае, если вы попытаетесь изменить строковый литерал во втором случае.
#include<string.h>int main(){char*str1 ="string Literal";constchar*str2 ="string Literal";char source[]="Sample string";
strcpy(str1,source);//No warning or error, just Undefined Behavior
strcpy(str2,source);//Compiler issues a warningreturn0;}
Вывод:
cc1: предупреждения обрабатываются как ошибки
prog.c: в функции 'main':
prog.c: 9: error: при передаче аргумента 1 'strcpy' отбрасывает классификаторы из целевого типа указателя
Обратите внимание, что компилятор предупреждает о втором случае, но не о первом.
Спасибо .. я смешивался с константным строковым литералом, который определяется как: char * name = "String Literal"; Изменение «Строкового литерала» не определено ..
Iceman
@ user1279782: Ой, подожди! Вы говорите о пуантах, указывающих на строковые литералы здесь? В этом случае Вы не должны изменять символ, на который nameуказывает пункт в любом случае. Это может привести к UB.
Alok Save
Да, это было главное. Так что в этом случае char * name и const char * name ведут себя одинаково, верно?
Iceman
4
Этот ответ либо крайне двусмысленный, либо просто неверный. Я бы сказал: «Вы не можете изменить символ, на который указывает имя, но Вы можете изменить символ, на который он указывает». Как не будучи в состоянии изменить сам указатель, но , будучи в состоянии изменить расположение памяти, на которую он указывает, что неверно: ideone.com/6lUY9s в качестве альтернативы для чистого C: ideone.com/x3PcTP
shroudednight
1
@shroudednight: Вам нужно узнать немного больше о неопределенном поведении, и нужно различать: разрешено и не должно быть сделано. :)
Alok Save
16
char mystring[101]="My sample string";constchar* constcharp = mystring;// (1)charconst* charconstp = mystring;// (2) the same as (1)char*const charpconst = mystring;// (3)
constcharp++;// ok
charconstp++;// ok
charpconst++;// compile error
constcharp[3]='\0';// compile error
charconstp[3]='\0';// compile error
charpconst[3]='\0';// ok// String literalschar* lcharp ="My string literal";constchar* lconstcharp ="My string literal";
lcharp[0]='X';// Segmentation fault (crash) during run-time
lconstcharp[0]='X';// compile error// *not* a string literalconstchar astr[101]="My mutable string";
astr[0]='X';// compile error((char*)astr)[0]='X';// ok
Ни один из ваших указателей не указывает на «константные строковые литералы» в соответствии с вопросом.
Кафе
Стоит отметить, что изменение char *значения приводит к ошибке сегментации, поскольку мы пытаемся изменить строковый литерал (который присутствует в постоянной памяти)
Divyanshu Maithani
10
Ни в том, ни в другом случае вы не можете изменить строковый литерал независимо от того, объявлен ли указатель на этот строковый литерал как char *или const char *.
Однако различие заключается в том, что если указатель равен, const char *то компилятор должен выдать диагностику, если вы пытаетесь изменить значение, на которое указывает указатель, но если указатель равен, char *то это не так.
«Ни в том, ни в другом случае вы не можете изменить строковый литерал, независимо от того, объявлено ли ... [оно] как char * или const char *» Я согласен, что программист не должен пытаться, но вы говорите, что каждый компилятор C на каждом Платформа будет отклонять код, организовывать сбой кода во время выполнения или что-то еще? Я считаю, что один файл может иметь определение и инициализацию, а другой файл может содержать extern ... nameи иметь *name = 'X';. На «правильной операционной системе» это может дать сбой, но на встроенных системах я бы ожидал, что он будет делать что-то конкретное для платформы / компилятора.
gbulmer
@gbulmer: Вы не можете изменить строковый литерал в правильной программе на Си. То, к чему может привести неправильная C-программа, ни здесь, ни там.
Кафе
@gbulmer: Одним из полезных определений является программа, которая не нарушает никаких ограничений, определенных стандартом языка Си. Другими словами, программа, которая изменяет строковый литерал, неверна так же, как и программа, которая разыменовывает нулевой указатель или выполняет деление на 0, неверно.
Кафе
Кафе - я думал, что это может быть то, что вы имели в виду. Тогда "Ни в том, ни в другом случае вы можете модифицировать строковый литерал», кажется, переутомление. Было бы правильно сказать: «В обоих случаях ограничения, указанные стандартом языка C, были нарушены, независимо ... Компилятор или система времени выполнения не могут выявить нарушения стандарта во всех случаях». Я предполагаю, что стандарт занимает позицию, что эффект не определен?
gbulmer
1
Когда стандарт не может утверждать что-либо в любом случае, я думаю, что определение поведения как «неопределенного» представляется точно правильной границей и полезным. Утвердить отношение «правильной C-программы» не может разыменовать нулевой указатель, звучит эквивалентно доказательству проблемы остановки. Но я не против. Я бы этого не сделал и не ожидал, что это сойдет с рук «бесплатно,
Скотт
4
СЛУЧАЙ 1:
char*str ="Hello";
str[0]='M'//Warning may be issued by compiler, and will cause segmentation fault upon running the programme
Выше указано, что str указывает на буквальное значение «Hello», которое жестко запрограммировано в двоичном изображении программы, которое помечено как доступное только для чтения в памяти, означает, что любое изменение в этом строковом литерале является недопустимым, и это приведет к ошибкам сегментации.
ДЕЛО 2:
constchar*str ="Hello";
str[0]='M'//Compile time error
ДЕЛО 3:
char str[]="Hello";
str[0]='M';// legal and change the str = "Mello".
Первое, что вы можете изменить, если хотите, второе, которое вы не можете. Читайте о constправильности (есть несколько хороших руководств о разнице). Там также, char const * nameгде вы не можете переписать это.
которая указывает на постоянный строковый литерал, и
constchar*cname
Т.е. дано
char*name ="foo";
и
constchar*cname ="foo";
Существует не так много различий между 2 и оба могут рассматриваться как правильные. Из-за долгого наследия C-кода строковые литералы имели тип « char[]нет» const char[], и существует множество более старых кодов, которые также принимают char *вместо const char *, даже если они не модифицируют аргументы.
Принципиальное отличие от 2 в общем состоит в том, что *cnameили cname[n]будет вычисляться для l-значений типа const char, тогда как *nameили name[n]будет оцениваться для l-значений типа char, которые являются модифицируемыми l-значениями . Соответствующий компилятор необходим для создания диагностического сообщения, если целью назначения не является изменяемое значение lvalue ; не нужно выдавать никаких предупреждений о присвоении lvalues типа char:
name[0]='x';// no diagnostics *needed*
cname[0]='x';// a conforming compiler *must* produce a diagnostics message
Компилятор не обязан останавливать компиляцию в любом случае; достаточно, чтобы он выдал предупреждение для назначения cname[0]. Полученная программа не является правильной программой. Поведение конструкции не определено . Может произойти сбой или, что еще хуже, может не произойти сбой и может изменить строковый литерал в памяти.
Ответы:
char*
является изменяемым указатель на изменяемый символ / строка.const char*
является изменяемым указатель на непреложный символ / строка. Вы не можете изменить содержимое местоположения, на которое указывает указатель. Кроме того, компиляторы обязаны выдавать сообщения об ошибках, когда вы пытаетесь это сделать. По той же причине преобразование изconst char *
вchar*
не рекомендуется.char* const
является неизменным указателем (он не может указывать на любое другое местоположение), но содержимое местоположения, на которое он указывает, является изменяемым .const char* const
является непреложным указатель на непреложный символ / строка.источник
char const *
char *
давать ошибку сегментации во время работы?const
если я хочу, чтобы компилятор выдавал ошибку, если я забыл и изменил данные по ошибке, верно?Вы можете изменить символ, на который
name
указывает, а также символ, на который он указывает.Вы можете изменить символ, на которыйname
указывает, но вы не можете изменить символ, на который он указывает.Исправление: Вы можете изменить указатель, но не символ, на который
name
указывает ( https://msdn.microsoft.com/en-us/library/vstudio/whkd4k6a(v=vs.100).aspx , см. «Примеры» ). В этом случаеconst
указатель относится кchar
звездочке, а не к ней.Согласно странице MSDN и http://en.cppreference.com/w/cpp/language/declarations ,
const
before*
является частью последовательности спецификатора decl, аconst
after*
является частью декларатора.За последовательностью спецификатора объявления могут следовать несколько объявлений, поэтому
const char * c1, c2
объявляетсяc1
какconst char *
иc2
какconst char
.РЕДАКТИРОВАТЬ:
Судя по комментариям, ваш вопрос, похоже, касается разницы между двумя объявлениями, когда указатель указывает на строковый литерал.
В этом случае вы не должны изменять символ, на который
name
указывает, так как это может привести к неопределенному поведению . Строковые литералы могут быть размещены в областях памяти, доступных только для чтения (реализация определяется), и пользовательская программа не должна изменять их в любом случае. Любая попытка сделать это приводит к неопределенному поведению.Таким образом, единственное отличие в этом случае (при использовании строковых литералов) заключается в том, что второе объявление дает вам небольшое преимущество. Компиляторы обычно выдают предупреждение в случае, если вы попытаетесь изменить строковый литерал во втором случае.
Пример онлайн-примера:
Вывод:
Обратите внимание, что компилятор предупреждает о втором случае, но не о первом.
источник
name
указывает пункт в любом случае. Это может привести к UB.источник
char *
значения приводит к ошибке сегментации, поскольку мы пытаемся изменить строковый литерал (который присутствует в постоянной памяти)Ни в том, ни в другом случае вы не можете изменить строковый литерал независимо от того, объявлен ли указатель на этот строковый литерал как
char *
илиconst char *
.Однако различие заключается в том, что если указатель равен,
const char *
то компилятор должен выдать диагностику, если вы пытаетесь изменить значение, на которое указывает указатель, но если указатель равен,char *
то это не так.источник
extern ... name
и иметь*name = 'X';
. На «правильной операционной системе» это может дать сбой, но на встроенных системах я бы ожидал, что он будет делать что-то конкретное для платформы / компилятора.СЛУЧАЙ 1:
Выше указано, что str указывает на буквальное значение «Hello», которое жестко запрограммировано в двоичном изображении программы, которое помечено как доступное только для чтения в памяти, означает, что любое изменение в этом строковом литерале является недопустимым, и это приведет к ошибкам сегментации.
ДЕЛО 2:
ДЕЛО 3:
источник
Первое, что вы можете изменить, если хотите, второе, которое вы не можете. Читайте о
const
правильности (есть несколько хороших руководств о разнице). Там также,char const * name
где вы не можете переписать это.источник
Вопрос в том, в чем разница между
которая указывает на постоянный строковый литерал, и
Т.е. дано
и
Существует не так много различий между 2 и оба могут рассматриваться как правильные. Из-за долгого наследия C-кода строковые литералы имели тип «
char[]
нет»const char[]
, и существует множество более старых кодов, которые также принимаютchar *
вместоconst char *
, даже если они не модифицируют аргументы.Принципиальное отличие от 2 в общем состоит в том, что
*cname
илиcname[n]
будет вычисляться для l-значений типаconst char
, тогда как*name
илиname[n]
будет оцениваться для l-значений типаchar
, которые являются модифицируемыми l-значениями . Соответствующий компилятор необходим для создания диагностического сообщения, если целью назначения не является изменяемое значение lvalue ; не нужно выдавать никаких предупреждений о присвоении lvalues типаchar
:Компилятор не обязан останавливать компиляцию в любом случае; достаточно, чтобы он выдал предупреждение для назначения
cname[0]
. Полученная программа не является правильной программой. Поведение конструкции не определено . Может произойти сбой или, что еще хуже, может не произойти сбой и может изменить строковый литерал в памяти.источник
Фактически,
char* name
это не указатель на константу, а указатель на переменную. Возможно, вы говорите об этом другом вопросе.В чем разница между char * const и const char *?
источник