out0FBox Ответов: 4

Разница в поведении между char* и int* в C++


Есть два фрагмента ниже . Нужно понять, почему char* успешен, а int* выдает ошибку. Попытка понять разницу в поведении между char* и int*
Заранее спасибо за вашу помощь .

Что я уже пробовал:

фрагмент 1 :

int *p;
Р=19;


соиь<&ЛТ;"п-вал"&ЛТ;&ЛТ;*Р<<епси;
cout<<"p addr"<&p<<endl;

о/р:
-----
main.cpp: в функции ‘int main()’:
main.cpp:14:3: error: недопустимое преобразование из ‘int’ в ‘int*’ [-fpermissive]
Р=19;

^~
===============================================================

фрагмент 2:

символ *в;
а="фубар";


соиь <&ЛТ;"вал = "&ЛТ;&ЛТ;*а на<<епси;
соиь <&ЛТ;"а = "&ЛТ;&ЛТ;а на<<епси;
соиь <&ЛТ;"а в addr = "&ЛТ;&ЛТ;&амп;в на<<епси;

о/р:
-----

$G++ и-о главном *.СРР
main.cpp: в функции ‘int main()’:
main.cpp:14:8: warning: ISO C++ запрещает преобразование Строковой константы в ‘char*’ [-Wwrite-strings]
а="фубар";
^~~~~~~
$главный
в Валь - = Ф
целое = фубар
a addr = 0x7ffed3404898
===============================================================

4 Ответов

Рейтинг:
28

OriginalGriff

int *p;
p=19;
p является "указателем на целое число", и 19 это целое число, а не адрес, поэтому компилятор жалуется, что вы не можете назначить целое число непосредственно указателю.
char *a;
a="fubar";
a это "указатель на символ", но "fubar" это string, который представляет собой массив символов с нулевым завершением. А имя массива - это указатель на первый элемент массива, который находится в определении языка и является фундаментальным для того, как работает язык.
С "fubar" состоит из символов, это эффективно (и действительно) "указатель на первый символ в строке", так что вы можете назначить его без проблем.


out0FBox

Спасибо за прекрасное объяснение .

Следовательно ,
символ *в;
a='f'; также должен выдавать недопустимую ошибку преобразования.
Я только что попробовал его, и он действительно дает недопустимую ошибку преобразования .

Ценю вашу помощь в этом вопросе .
С уважением

OriginalGriff

Всегда пожалуйста!

Рейтинг:
2

Rick York

Сообщение говорит само за себя - вы не можете преобразовать строковую константу в 'char *'. Причина в том, что тогда можно было бы изменить константу, а это недопустимо. Чтобы сделать эту компиляцию и запустить ее, измените объявление a на 'const char *a', и тогда она будет работать.

-редактировать-

Что касается фрагмента 1 : он объявляется как указатель, и следующая строка присваивает этому указателю значение 19. Это вряд ли будет действительный адрес, и именно на него ссылается сообщение. Кроме того, вам, вероятно, на самом деле нужен не адрес указателя, а его значение, которое было бы адресом, который он содержит. Это означает, что линия должна быть изменена :

cout << "p addr" << p << endl;
и это будет отображать адрес, который содержит указатель. Вот лучшее использование указателя на целое число :
int ivalue = 0;
int* iptr = &ivalue;   // set iptr to the address of ivalue
*iptr = 42;            // set the value of the integer pointed to
теперь ivalue будет иметь значение 42. Ключевым моментом здесь является то, что значение указателя-это адрес, который он содержит. Чтобы получить данные по этому адресу, вы должны разыменовать указатель, и именно это делает звездочка.


out0FBox

Привет Рик,
Спасибо за ответ.
Однако предупреждение для char* не является проблемой . Я хотел знать, почему это не удалось для фрагмента 1 .

С уважением

Рейтинг:
2

CPallini

Сравнение несправедливо: фрагменты кода не эквивалентны.
Вы должны сравнить либо

// snippet a.1
int *p;
p = 19;

cout << "p val"<< *p << endl;
cout << "p addr" << p << endl;


// snippet a.2
char *s;
s = 'a';

cout << "s val"<< *s << endl;
cout << "s addr" << s << endl;
Выходные данные компилятора:
[...]: error: invalid conversion from ‘int’ to ‘int*’ [-fpermissive]
  p = 19;
      ^~
[...]: error: invalid conversion from ‘char’ to ‘char*’ [-fpermissive]
  s = 'a';
      ^~~




или


// snippet b.1
const int ia[] = {1,2,3};
int *p;
p = ia;

cout << "p val"<< *p << endl;
cout << "p addr" << p << endl;

// shippet b.2
char *s;
s = "alpha";

cout << "s val"<< *s << endl;
cout << "s addr" << s << endl;
Выходные данные компилятора
[...]: error: invalid conversion from ‘const int*’ to ‘int*’ [-fpermissive]
  p = ia;
      ^~
[...]: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
  s = "alpha";
      ^~~~~~~

В приведенном выше случае (фрагменты b) компилятор фактически рассматривает char как-то по-особенному (наверное, это и есть C наследие).




[обновление]
Цитата:
Но чего я не знаю, так это почему обычный целочисленный указатель не может указывать на целое число const.
Указатель мочь например, укажите на целочисленную константу:
const int myconst = 10;
const int * p = &myconst; // p is a pointer to const (NOT a const pointer)
printf("Address = %p, value = %d\n", p, *p);

Однако вы не можете произвольно назначить ему адрес (как в вашем примере):
const int * p = 19; // ERROR

это явно неправильно.


Цитата:
Мое первое предположение заключается в том , что разрешение so позволит изменить значение const int через указатель
Это довольно правильно: вы можете назначить адрес целого числа const только указатель на целое число const (Не указатель const).


Цитата:
предположение втором это константный указатель должен использоваться, чтобы указать на переменную const
Нет.
  • Указатель на целое число const должен использоваться для указания на целое число const.
  • Указатель const-это указатель, значение которого (то есть адрес, на который он указывает) не может быть изменено.
Напр.
const int myconst = 10;
  const int * p = &myconst; // p is pointer to const int
  int i = 0;
  int j = 0;
  int * const q = &i; // q is a const pointer to int
  *q = 50; // i.e. i=50, it is OK, since q points to a variable 
   q = &j; // ERROR, cannot change the address q points to 

[/обновление]


out0FBox

Да. Сравнение отключено в моем примере вопроса.
Согласно фрагменту b.1, если массив не является целым числом cont, то ошибки быть не должно.
Но чего я не знаю, так это почему обычный целочисленный указатель не может указывать на целое число const.
Мое первое предположение заключается в том , что разрешение so позволит изменить значение const int с помощью указателя. Второе предположение состоит в том, что указатель const должен использоваться для указания на переменную const.
Дайте мне знать, если мои предположения верны.

CPallini

Смотрите мое обновленное решение.

Рейтинг:
1

Daniel Pfeffer

Постоянная символьная строка в C++ имеет тип 'const char*', который большинство компиляторов позволяют назначить 'char*' (возможно, с предупреждением). OTOH, 'int' (например, 19) никогда не совместим с 'int*'. Вы должны разыменовать указатель таким образом:

*Р = 19;

(Есть небольшое исключение из этого правила - указателю может быть присвоено значение 0, что в данном контексте эквивалентно nullptr. Однако новые программы должны использовать nullptr, а не 0.)


out0FBox

Спасибо за немедленный ответ . Я искал ответ, близкий к тому, что OriginalGriff опубликовал выше. Но это тоже помогает.

С уважением