Разница между char * и const char *? - PullRequest
147 голосов
/ 23 марта 2012

В чем разница между

char* name

, который указывает на постоянный строковый литерал, и

const char* name

Ответы [ 9 ]

337 голосов
/ 23 марта 2012

char* является изменяемым указателем на изменяемый символ / строку.

const char* является изменяемым указателем на неизменный символ / строка.Вы не можете изменить содержимое местоположения, на которое указывает указатель.Кроме того, компиляторы обязаны выдавать сообщения об ошибках, когда вы пытаетесь это сделать.По той же причине преобразование из const char * в char* не рекомендуется.

char* const является неизменным указателем (он не может указывать на любое другое местоположение) , но содержимое местоположения, на которое он указывает изменяемый .

const char* const - это неизменный указатель на неизменный символ / строку.

41 голосов
/ 23 марта 2012
char *name

Вы можете изменить символ, на который указывает name, а также символ, на который он указывает.

const char* 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 до * является частьюпоследовательность спецификатора decl, а const после * является частью декларатора.За последовательностью спецификатора объявления могут следовать несколько объявлений, поэтому const char * c1, c2 объявляет c1 как const char * и c2 как const char.

РЕДАКТИРОВАТЬ:

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

В этом случае вы не должны изменять символ, на который указывает 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: предупреждения рассматриваются как ошибки
prog.c: в функции 'main':
prog.c: 9: error:передача аргумента 1 в 'strcpy' отбрасывает квалификаторы из целевого типа указателя

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

15 голосов
/ 23 марта 2012
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
9 голосов
/ 23 марта 2012

Ни в том, ни в другом случае вы не можете изменить строковый литерал независимо от того, объявлен ли указатель на этот строковый литерал как char * или const char *.

Однако разница в том, что если указатель равен const char *, то компилятор должен выдать диагностику, если вы пытаетесь изменить значение, на которое указывает указатель, но если указатель равен char *, то это не так.

2 голосов
/ 15 ноября 2017

Случай 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".
2 голосов
/ 23 марта 2012

Первое, что вы можете изменить, если хотите, второе, которое вы не можете. Читайте о const правильности (есть несколько хороших руководств о разнице). Также есть char const * name, где вы не можете его переписать.

1 голос
/ 24 августа 2017

Вопрос в том, в чем разница между

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, которые изменяемые lvalues ​​. Соответствующий компилятор необходим для создания диагностического сообщения, если цель назначения не является изменяемым lvalue ; нет необходимости предупреждать о присвоении lvalues ​​типа char:

name[0] = 'x'; // no diagnostics *needed*
cname[0] = 'x'; // a conforming compiler *must* produce a diagnostics message

Компилятору не требуется , чтобы остановить компиляцию в любом случае; достаточно, чтобы он выдал предупреждение для назначения cname[0]. Полученная программа не является правильной программой. Поведение конструкции: undefined . Может произойти сбой или, что еще хуже, может не произойти сбой и может изменить строковый литерал в памяти.

1 голос
/ 23 марта 2012

На самом деле, char* name - это не указатель на константу, а указатель на переменную. Возможно, вы говорите об этом другом вопросе.

В чем разница между char * const и const char *?

0 голосов
/ 12 июня 2017

Просто приведу дополнительный пример:

    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'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!

Вы можете запустить ее и увидеть вещи лучше для себя.

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