Давайте рассмотрим ваш пример:
void showInt(int* numbers) // (1)
{
numbers += 3; // (2)
}
int main()
{
int* a = 10; // (3)
showInt(a); // (4)
return 0;
}
(1) numbers
переменная является копией переменной, переданной этой функции;
(2) из-за (1) все изменения, сделанные здесь numbers
, останутся только в этой функции; значение исходной переменной, переданной этой функции, останется прежним! Но обратите внимание на следующее: вы не можете изменить значение указателя (a
), переданного функции, но с помощью копии этого указателя (numbers
) вы можете изменить значение, на которое она указывает!
Это главный трюк - если у вас есть адрес внутри функции, вы можете писать по этому адресу, и эти изменения остаются после возврата функции. Запись по адресу включает разыменование указателя, но вы, к счастью, этого не сделали - я говорю «к счастью», потому что переданный вами адрес был просто произвольным адресом в памяти (10). Если вы попытаетесь написать по адресу 10, ваша программа, скорее всего, вылетит.
(3) Вы объявили a
типа «указатель на int», поэтому предполагается, что это значение является адресом некоторого объекта int
. Вы допустили здесь опасную ошибку, так как предположили, что 10 был действительным адресом некоторого int, но вы на самом деле не знаете, что находится по этому адресу.
(4) Вы передаете копию переменной a
в функцию. Функция сохраняет значение в переменной numbers
и увеличивает его. Таким образом, numbers
теперь содержит адрес 13 (а не адрес некоторой целочисленной переменной, значение которой равно 13!). a
остается тем же, хотя и имеет то же значение, 10.
Вы, вероятно, хотели что-то вроде этого:
void showInt(int* numbers)
{
*numbers += 3; // (1)
}
int main()
{
int a = 10; // (2)
showInt(&a); // (3)
return 0;
}
Функция
(1) изменяет значение по адресу, который хранится в numbers
. Указатель разыменовывается.
(2) У нас должен быть действительный адрес некоторой переменной int, а не просто случайно выбранный адрес (например, 10). Поэтому мы объявляем переменную типа int, a
. Его адрес &a
.
(3) Адрес a
передается в showInt
через переменную numbers
, и теперь функция может записывать в этот адрес (который теперь является действительным адресом объекта int - a
) и таким образом изменять значение a
. Когда функция возвращается, a
имеет значение 13. Обратите внимание, что адрес a
здесь не изменяется ни в какой момент времени.