Указатели в параметрах функции

Последнее обновление: 03.03.2023

Параметры функции в C++ могут представлять указатели. Указатели передаются в функцию по значению, то есть функция получает копию указателя. В то же время копия указателя будет в качестве значения иметь тот же адрес, что оригинальный указатель. Поэтому используя в качестве параметров указатели, мы можем получить доступ к значению аргумента и изменить его.

Например, пусть у нас будет простейшая функция, которая увеличивает число на единицу:

#include <iostream>

void increment(int);

int main()
{
    int n {10};
    increment(n);
    std::cout << "main function: " << n << std::endl;
}
void increment(int x)
{
    x++;
    std::cout << "increment function: " << x << std::endl;
}

Здесь переменная n передается в качестве аргумента для параметра x. Передача происходит по значению, поэтому любое изменение параметра x в функции increment никак не скажется на значении переменной n. Что мы можем увидеть, запустим программу:

increment function: 11
main function: 10

Теперь изменим функцию increment, использовав в качестве параметра указатель:

#include <iostream>

void increment(int*);

int main()
{
    int n {10};
    increment(&n);
    std::cout << "main function: " << n << std::endl;
}
void increment(int *x)
{
    (*x)++; // получаем значение по адресу в x и увеличиваем его на 1
    std::cout << "increment function: " << *x << std::endl;
}

Для изменения значения параметра применяется операция разыменования с последующим инкрементом: (*x)++. Это изменяет значение, которое находится по адресу, хранимому в указателе x.

Поскольку теперь функция в качестве параметра принимает указатель, то при ее вызове необходимо передать адрес переменной: increment(&n);.

В итоге изменение параметра x также повлияет на переменную n, потому что оба они хранят адрес на один и тот же участок памяти:

increment function: 11
main function: 11

В то же время поскольку аргумент передается в функцию по значению, то есть функция получает копию адреса, то если внутри функции будет изменен адрес указателя, то это не затронет внешний указатель, который передается в качестве аргумента:

#include <iostream>

void increment(int*);

int main()
{
    int n {10};
    int *ptr {&n};
    increment(ptr);
    std::cout << "main function: " << *ptr << std::endl;
}
void increment(int *x)
{
	int z {6};
	x = &z;		// переустанавливаем адрес указателя x
    std::cout << "increment function: " << *x << std::endl;
}

В функцию increment передается указатель ptr, который хранит адрес переменной n. При вызове функция increment получает копию этого указателя через параметр x. В функции изменяется адрес указателя x на адрес переменной z. Но это никак не затронет указатель ptr, так как он предствляет другую копию. В итоге поле переустановки адреса указатели x и ptr будут хранить разные адреса.

Результат работы программы:

increment function: 6
main function: 10

Константные параметры-указатели

Параметры, которые преставляют указатели, могут быть константными.

#include <iostream>
 
void print(const int*); // константный параметр

int main()
{
    int n {10};
    print(&n);
}
void print(const int *x)
{
    std::cout << *x << std::endl;
}

По константному параметру мы не можем изменить значение. То есть фактически такие параметры представляют указатели на константу. Поэтому константные параметры полезны, когда необходимо передать в функцию адрес константы - в этом случае параметр обязательно должен быть константным:

#include <iostream>
 
void print(const int*); // константный параметр

int main()
{
    const int n {10};
    print(&n);  // передаем адрес константы
}
void print(const int *x)
{
    std::cout << *x << std::endl;
}

При этом константность параметра не означает, что мы не можем изменить адрес, хранимый в указателе, например, следующим образом:

void print(const int *x)
{
    int z{2};
    x = &z;     // меняем адрес в указателе на адрес переменной z
    std::cout << *x << std::endl;   // 2
}

Чтобы гарантировать, что не только значение по указателю не будет меняться, но и само значение указателя (хранимый в нем адрес) не будет меняться, надо определить указатель как константный:

#include <iostream>
 
void print(const int*); // константный параметр

int main()
{
    const int n {10};
    print(&n);
}
void print(const int* const x)  // константный указатель на константу
{
    int z{2};
    //x = &z; // значение указателя нельзя изменить
    std::cout << "z = " << z << std::endl;      // z = 2
    std::cout << "*x = " << *x << std::endl;    // *x = 10
}

Параметры по ссылке или параметры-указатели

Параметры, передаваемые по ссылке, и параметры-указатели похожи в том плане, что оба эти вида параметров позволяют менять значения передаваемых в них переменных. Единственной отличительной особенностью указателя является то, что он может иметь значение nullptr, в то время как ссылка всегда должна ссылаться на что-то. Поэтому, если необходимо, что параметр не имел никакого значения, то можно использовать указатели. Единственное, что в этом случае необходимо проверять указатель на значение nullptr перед его использованием.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850