#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
. Помните, что anint
не может содержать адреса памяти (это работа указателей), поэтому вы получаете ошибку компиляции. Кроме того, обратите внимание, что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
означает одно и то же.