2013-04-12 2 views
3

Я думаю, что строковые литералы в c++ - это тип const char*. И вы не можете назначить объект const char* объекту non-constant char*. Но в Visual Studio 2010. Следующий код может компилироваться без ошибок или предупреждений, что, однако, приведет к ошибке выполнения.Почему я могу присвоить строковые литералы указателю char *

int main(void) 
{  
    char *str2 = "this is good"; 
    str2[0] = 'T'; 
    cout << str2; 
    getchar(); 
    return 0; 
} 

И если мы не изменить значение строки, чтение значения в порядке:

for(char *cp = str2; *cp !=0; ++cp) { 
    printf("char is %c\n", *cp); 
} 
getch(); 
return 0; 

Так почему мы можем присвоить константный символ * к * полукокса здесь?

+0

@unkulunkulu Ответ немного отличается от C++: согласно [lex.string], это _array of const char_ в C++ – dyp

+0

@DyP, ответ на связанный вопрос охватывает C++ – unkulunkulu

+0

@unkulunkulu О, sry, ты прав. Тем не менее, код выше _invalid_ в C++, см. [Diff.lex] – dyp

ответ

3

Вопрос находится под VC++, но в GCC имеет значимое предупреждение:

предупреждение: не рекомендуется использовать преобразование из строки константу 'символ *' [-Wwrite-строк]

Это предупреждение подразумевает, что компилятор будет применять неявное преобразование, несмотря на константы const/non-const. Таким образом, этот код нормально (без каких-либо изменений в время выполнения):

char *str2 = "this is good"; 

Однако изменение str2 приводит к неопределенному поведению.

1

Строковые литералы, действительно, постоянны. Однако, массивы распадаются на указатели, и вы приняли не- const указатель на первый элемент массива:

char *str2 = "this is good"; 

Изменение любого значения константных доходности массив символов неопределенное поведение.

Это не будет скомпилировано под gcc 4.7.2. Если вы включите уровни предупреждений до уровня предупреждения 4 под MSVC, он, вероятно, также выдаст предупреждение.

+0

[diff.lex] явно указывает: 'char * p =" abc ";' недопустим в C++. Теперь я смущен. – dyp

+0

@Dyp Он действителен в vC++, но вы не можете изменить значение. – zoujyjs

+0

Итак, msvc берет литералы как char *, правильно ли это? – zoujyjs

1

Давайте посмотрим на C++ 03, а не C++ 11:

[conv.array]

Строковый литерал (2.13.4), не широкий строковый литерал может быть преобразован в rvalue типа «указатель на char»;

На самом деле, любая узкая строковый литерал имеет тип «массив п сопзЬ полукокс», но, как вы можете прочитать выше, есть (уже устаревшие C++ 03) функция неявно преобразовать их в rvalues ​​типа char *.

Тем не менее вам не разрешено изменять содержимое строки, как если бы вы сделали const_cast: Объект, на который указывает указатель, был объявлен как const, поэтому никакая модификация не разрешена (неопределенное поведение).

+0

приятно! Таким образом, все же это const char *, но есть неявное преобразование. Понял! – zoujyjs

+0

@zoujyjs Почти. Есть два перехода. [conv.array], с текстом в скобках от меня: «abc» преобразуется [из массива 4 const char] в «указатель на const char» как преобразование от массива к указателю, а затем в «указатель на char», как конверсия квалификации. – dyp

Смежные вопросы