Разница между char* и const char*?
9 ответов
char*
Это mutable указатель на mutable символ/строку.
const char*
это mutable указатель на неизменяемые символ/строку. Вы не можете изменить содержимое местоположения, на которое указывает этот указатель. Кроме того, компиляторы должны выдавать сообщения об ошибках при попытке сделать это. По той же причине, преобразование из const char *
to char*
устарела.
char* const
это неизменяемые указатель (он не может указывать на любое другое место)но содержимое местоположение точки mutable.
const char* const
это неизменяемые указатель на неизменяемые символ/строку.
char *name
вы можете изменить символ, который name
указывает, а также символ, на который он указывает.
const char* name
вы можете изменить символ, который name
указывает, но вы не можете изменить символ, на который он указывает.
устранение: вы можете изменить указатель, но не чар, которым name
указывает на (https://msdn.microsoft.com/en-us/library/vstudio/whkd4k6a (v=против 100).aspx, см. "примеры"). В этом случае const
спецификатор применяется к char
, а не звездочка.
по данным на странице MSDN и http://en.cppreference.com/w/cpp/language/declarations на const
до *
является частью последовательности спецификатора decl, в то время как const
после *
часть Декларатора.
Последовательность спецификатора объявления может быть затем следует несколько деклараторов, поэтому const char * c1, c2
объявляет c1
as const char *
и c2
as const char
.
EDIT:
из комментариев ваш вопрос, похоже, спрашивает о разнице между двумя объявлениями, когда указатель указывает на строковый литерал.
в этом случае не должен изменить символ, к которому name
баллов, так как это может привести к неопределено Поведение.
Строковые литералы могут быть выделены в областях памяти только для чтения (реализация определена), и пользовательская программа не должна изменять его в любом случае. Любая попытка сделать это приводит к неопределенному поведению.
так что единственная разница в этом случае (использования со строковыми литералами) заключается в том, что второе объявление дает вам небольшое преимущество. Компиляторы обычно дают вам предупреждение, если вы попытаетесь изменить строковый литерал во втором случай.
#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: предупреждения рассматриваются как ошибки
еда.c: в функции ' main’:
еда.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] = ''; // compile error
charconstp[3] = ''; // compile error
charpconst[3] = ''; // 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
где вы не можете переопределить его.
на самом деле char* name
- Это не указатель на константу, а указатель на переменную. Возможно, вы говорите о другом вопросе.
Пример 1:
char *str = "Hello";
str[0] = 'M' //No warning or error, just Undefined Behavior
выше устанавливает str, чтобы указать на литерал "Hello", который жестко закодирован в двоичном образе программы, который помечен как только для чтения в памяти, означает, что любое изменение в этом строковом литерале незаконно, и это вызовет ошибки сегментации.
Пример 2:
const char *str = "Hello";
str[0] = 'M' //Compiler issues a warning
случай 3:
char str[] = "Hello";
str[0] = 'M'; // legal and change the str = "Mello".
просто, чтобы дать дополнительный пример:
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''.
//Here's 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's do something more interesting:
char* charptr2="hubble";
strcpy(charptr, charptr2); // --------> Oops! Sorry, this is not valid!
Вы можете запустить его и посмотреть вещи лучше для себя.
вопрос в том, в чем разница между
char *name
что указывает на постоянный строковый литерал и
const char *cname
т. е. учитывая
char *name = "foo";
и
const char *cname = "foo";
нет большой разницы между 2 и оба можно рассматривать как правильные. Из-за длительного наследия кода C строковые литералы имели тип char[]
, а не const char[]
, и есть много старого кода, который также принимает char *
вместо const char *
, даже если они не изменяют аргументы.
принципиальным отличием 2 в целом является то, что *cname
или cname[n]
будет оценивать lvalues типа const char
, а *name
или name[n]
будет оценивать lvalues типа char
, которые модифицируемые lvalues. Соответствующий компилятор необходим для создания диагностического сообщения, если цель назначения не является изменяемой lvalue; ему не нужно произвести никакое предупреждение дальше назначение lvalues типа char
:
name[0] = 'x'; // no diagnostics *needed*
cname[0] = 'x'; // a conforming compiler *must* produce a diagnostics message
компилятор не требуются чтобы остановить компиляцию в любом случае; достаточно, чтобы она произвела предупреждение за задание cname[0]
. Полученная программа не является правильно