В чем разница в этом примере разыменования указателей?

#c #pointers

#c #указатели

Вопрос:

Итак, в моем классе есть два примера, и я не уверен, почему один работает, а другой нет.

 int numSides = 3;
int *valPointer = amp;numSides;
PrintValue(valPointer);
 

Выводит 3.

 int numSides = 3;
int* valPointer;
*valPointer = amp;numSides;
PrintValue(valPointer);
 

Это не работает, но почему?

примечание к классу int : значение не может быть присвоено int* .

Комментарии:

1. Эта строка: *valPointer = amp;numSides , пытается присвоить адрес numSides памяти, на которую указывает valPointer . Помните, что an int не может содержать адреса памяти (это работа указателей), поэтому вы получаете ошибку компиляции. Кроме того, обратите внимание, что valPointer это неинициализированное , что означает, что присвоение ему любого значения является неопределенным поведением .

2. Если быть точным: *valPointer = amp;numSides; поведение не определено , потому что разыменовывается неинициализированный указатель. Никто не может сказать, что на самом деле происходит.

3. *valPointer = numSides; было бы неопределенным поведением; OTOH *valPointer = amp;numSides; четко определен в том смысле, что он всегда будет приводить к ошибке во время компиляции. 🙂

Ответ №1:

 int* valPointer;
*valPointer = amp;numSides;
 

Вышесказанное неверно — вы пытаетесь установить (целое число, на которое valPointer указывает) на адрес, что не имеет смысла, потому что адреса и целые числа (вообще говоря) не взаимозаменяемы.

Возможно, вы имели в виду это вместо этого?

 int* valPointer;
valPointer = amp;numSides;
 

… это будет указывать valPointer на numSides .

Комментарии:

1. но почему это выполнимо в первом примере. В первом примере мы говорим int *valPointer = amp;numSides;

2. @FranciscoGutierrezRamirez Причина заключается в типах присваивания: введите слева и введите справа, они должны быть совместимы. Один — указатель, другой — целое число,

3. @FranciscoGutierrezRamirez в первом примере вы объявляете указатель на int и присваиваете ему значение point to numSides . Вы должны интерпретировать это как int * valPointer = amp;numSides; , а не как int *valPointer = amp;numSides; Другими словами, * в объявлении переменной является частью типа переменной, тогда * как во втором примере это оператор разыменования, что совершенно другое, хотя этоиспользует тот же символ.

Ответ №2:

Программа:

 void PrintValue(int*);

void f() {
  int numSides = 3;
  int *valPointer;
  *valPointer = amp;numSides;
  PrintValue(valPointer);
}
 

Результаты компиляции:

Лязг:

 <source>:6:17: error: incompatible pointer to integer conversion assigning to 'int' from 'int *'; remove amp;
  *valPointer = amp;numSides;
                ^~~~~~~~~
1 error generated.
Compiler returned: 1
 

Gcc:

 <source>: In function 'void f()':
<source>:6:17: error: invalid conversion from 'int*' to 'int' [-fpermissive]
    6 |   *valPointer = amp;numSides;
      |                 ^~~~~~~~~
      |                 |
      |                 int*
Compiler returned: 1
 

Компилятор Microsoft:

 example.cpp
<source>(6): error C2440: '=': cannot convert from 'int *' to 'int'
<source>(6): note: There is no context in which this conversion is possible
Compiler returned: 2
 

Каждый компилятор по-своему говорит, в чем проблема в сообщениях об ошибках.

  • несовместимый указатель с целочисленным преобразованием, присваивающим ‘int’ из ‘int *’
  • недопустимое преобразование из ‘int *’ в ‘int’
  • невозможно преобразовать из ‘int *’ в ‘int’

Clang даже дает предложение:

  • удалить ‘amp;’

Что не обязательно правильно.

Ответ №3:

int *valPointer = amp;numSides;

Это объявляет переменную, valPointer , типа int * , и сохраняет numSides в ней адрес.

int* valPointer; *valPointer = amp;numSides;

Это объявляет переменную, valPointer , типа int * , но не инициализирует ее для указания на какое-либо конкретное местоположение. Адрес, который он содержит, — это просто любой мусор, который оказался в стеке. Затем он разыменовывает valPointer , что является ошибкой, поскольку valPointer никогда не инициализировалось, и пытается сохранить адрес numSides в этом местоположении.

Я думаю, что важным моментом, который вам нужен, является то, что * используется для разыменования указателя при использовании отдельно (например *valPointer ), но он является частью типа при использовании в объявлении (например int *valPointer ). Также обратите внимание, что при использовании в объявлении не имеет значения, есть ли пробел между типом и * или переменной * and ; то есть, int *foo и int *foo означает одно и то же.