Какая разница между
char* name
который указывает на константный строковый литерал и
const char* name
Какая разница между
char* name
который указывает на константный строковый литерал и
const char* name
char*
является изменяемым указателем на изменяемый символ/строку.
const char*
является изменяемым указателем на неизменяемый символ/строку. Вы не можете изменить содержимое местоположения, на которое указывает указатель. Кроме того, компиляторы обязаны выдавать сообщения об ошибках, когда вы пытаетесь это сделать. По той же причине преобразование из const char *
в char*
не рекомендуется.
char* const
является неизменным указателем (он не может указывать ни на какое другое местоположение) , но содержимое местоположения, на которое он указывает, является изменяемым.
const char* const
является неизменяемым указателем на неизменяемый символ/строку.
char *name
Вы можете изменить char, на который указывают точки name
, а также char, на которые он указывает.
const char* name
Вы можете изменить char, на который name
указывает, но вы не можете изменить char, на котором он указывает.
: Вы можете изменить указатель, но не char, на который указывает 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
до *
является частью последовательности определения-спецификатора, а const
после *
является частью декларатора.
Последовательность спецификатора объявления может сопровождаться несколькими деклараторами, поэтому const char * c1, c2
объявляет c1
как const char *
и c2
как const char
.
EDIT:
Из комментариев, ваш вопрос, кажется, спрашивает о различии между двумя объявлениями, когда указатель указывает на строковый литерал.
В этом случае вы не должны изменять char, на который указывает name
, так как это может привести к Undefined Поведение.
Строковые литералы могут быть выделены в областях памяти только для чтения (реализация определена), и пользовательская программа не должна изменять ее в любом случае. Любая попытка сделать это приводит к Undefined Поведение.
Таким образом, единственное различие в этом случае (использование со строковыми литералами) состоит в том, что второе объявление дает вам небольшое преимущество. Компиляторы обычно выдают вам предупреждение, если вы попытаетесь изменить строковый литерал во втором случае.
#include <string.h>
int main()
{
char *str1 = "string Literal";
const char *str2 = "string Literal";
char source[] = "Sample string";
strcpy(str1,source); //No warning or error, just Undefined Behavior
strcpy(str2,source); //Compiler issues a warning
return 0;
}
Выход:
cc1: предупреждения обрабатываются как ошибки
prog.c: В функции 'main:
prog.c: 9: ошибка: передача аргумента 1 из 'strcpy отбрасывает квалификаторы из целевого типа указателя
Обратите внимание, что компилятор предупреждает о втором случае, но не для первого.
char mystring[101] = "My sample string";
const char * constcharp = mystring; // (1)
char const * 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 literals
char * lcharp = "My string literal";
const char * lconstcharp = "My string literal";
lcharp[0] = 'X'; // Segmentation fault (crash) during run-time
lconstcharp[0] = 'X'; // compile error
// *not* a string literal
const char astr[101] = "My mutable string";
astr[0] = 'X'; // compile error
((char*)astr)[0] = 'X'; // ok
В любом случае вы не можете изменить строковый литерал, независимо от того, объявлен ли указатель на этот строковый литерал как char *
или const char *
.
Однако разница заключается в том, что если указатель const char *
, тогда компилятор должен дать диагностику, если вы попытаетесь изменить указанное значение, но если указатель char *
, то это не так.
Первое, что вы можете изменить, если хотите, второе - вы не можете. Прочитайте о правильности const
(там есть некоторые рекомендации по поводу разницы). Существует также char const * name
, где вы не можете его перепечатать.
ДЕЛО 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:
const char *str = "Hello";
str[0] = 'M' //Compile time error
СЛУЧАЙ 3:
char str[] = "Hello";
str[0] = 'M'; // legal and change the str = "Mello".
Собственно, char* name
не является указателем на константу, а указателем на переменную. Вы можете говорить об этом другом вопросе.
Вопрос в том, что разница между
char *name
который указывает на константный строковый литерал и
const char *cname
т.е. учитывая
char *name = "foo";
и
const char *cname = "foo";
Существует не так уж много различий между двумя, и оба могут рассматриваться как правильные. Из-за длительного наследия кода C строковые литералы имели тип char[]
, а не const char[]
, и есть много более старого кода, которые также принимают char *
вместо const char *
, даже если они не измените аргументы.
Основное отличие 2 в общем состоит в том, что *cname
или cname[n]
будет оценивать lvalues типа const char
, тогда как *name
или name[n]
будет оценивать lvalues типа char
, которые изменяемые значения l. Для получения сообщения диагностики требуется соответствующий компилятор, если target назначения не является изменяемым значением l; он не должен вызывать предупреждения о присвоении lvalues типа char
:
name[0] = 'x'; // no diagnostics *needed*
cname[0] = 'x'; // a conforming compiler *must* produce a diagnostics message
Компилятор не обязан останавливать компиляцию в любом случае; достаточно, чтобы он выдавал предупреждение для назначения cname[0]
. Полученная программа не является правильной программой. Поведение конструкции undefined. Это может привести к сбою или, что еще хуже, может не привести к сбою и может изменить строковый литерал в памяти.
Просто чтобы привести дополнительный пример:
std::cout << typeid(2.3).name() << '\n'; // -----> prints "double" simply because
//2.3 is a double
//But the "double" returned by typeid(2.3).name() is indeed a
//const char * which consists of 'd','o','u','b','l','e'and'\0'.
//Here a simple proof to this:
std::cout << typeid(typeid(2.3).name()).name() << '\n'; //prints: "const char *"
const char* charptr
charptr = typeid(2.3).name();
std::cout << charptr[3]; // ---------> prints: "b"
(Я использую библиотеку typeinfo: http://www.cplusplus.com/reference/typeinfo/type_info/name)
//Now let do something more interesting:
char* charptr2="hubble";
strcpy(charptr, charptr2); // --------> Oops! Sorry, this is not valid!
Вы можете запустить его и лучше увидеть для себя.