В этой статье мы с вами рассмотрим понятие указателя в языке C++. Указатель (англ. pointer) в C++ - это переменная, которая содержит адрес памяти другой переменной. Как и любая другая переменная, указатель должен быть сначала объявлен перед тем, как вы начнёте его использовать. Для объявления переменной-указателя используется символ "звёздочки" ( * ), идущий после того типа данных, на который и будет указывать переменная-указатель.
Давайте сразу посмотрим на небольшой пример использования указателя в программе на C++, чтобы прояснить всё вышесказанное:
#include <iostream>
using namespace std;
int main() {
// объявляем три переменные целого типа с именами a, b и c
int a = 10, b = 20, c = 30;
// объявляем переменную-указатель с именем p
int* p;
// выводим на экран консоли значения всех трёх переменных
cout << "The value of 'a' is: " << a << endl;
cout << "The value of 'b' is: " << b << endl;
cout << "The value of 'c' is: " << c << endl;
// присваиваем указателю значение адреса памяти, по которому хранится значение для переменной a
p = &a;
cout << "Pointer address is currently " << p << endl; // выводим значение указателя (это адрес памяти для переменной a)
cout << "Pointer value is currently " << *p << endl; // выводим значение "содержимого" по тому адресу памяти, который хранит сейчас p
// присваиваем указателю значение адреса памяти, по которому хранится значение для переменной b
p = &b;
cout << "Pointer address is currently " << p << endl; // выводим значение указателя (это адрес памяти для переменной b)
cout << "Pointer value is currently " << *p << endl; // выводим значение "содержимого" по тому адресу памяти, который хранит сейчас p
// присваиваем указателю значение адреса памяти, по которому хранится значение для переменной c
p = &c;
cout << "Pointer address is currently " << p << endl; // выводим значение указателя (это будет адрес памяти для переменной c)
cout << "Pointer value is currently " << *p << endl; // выводим значение "содержимого" по тому адресу памяти, который хранит сейчас p
}
Я специально снабдил код примера комментариями, чтобы каждая строка была полностью понятна, но всё же остановлюсь на ключевых моментах этого примера. Вначале мы объявили три целочисленных переменных с именами a, b и c, проинициализировав их значениями 10, 20 и 30, соответственно. Дальше мы объявили переменную-указатель с именем p. Как видите, в её объявлении указан тип int*, что означает "указатель на значение типа int". Как можно видеть, в объявлении переменной p мы сначала не присваиваем ей никакого конкретного значения, это значит, что p будет содержать какое-то непредсказуемое значение, т.е. какой-то адрес, который не указывает на что-то конкретное. Обращаться к переменной-указателю на этой стадии нельзя: если вы попытаетесь использовать переменную-указатель до её инициализации, компилятор C++ не позволит этого сделать и выдаст ошибку, а такая программа у вас просто не скомпилируется.
Дальше мы просто выводим значения наших переменных a, b и c на экран консоли. Это нужно для последующей части нашей программы-примера, чтобы сравнить результаты доступа к переменным с помощью нашей переменной-указателя p. После этого мы присваиваем нашей переменной p значение адреса переменной a:
p = &a;
Этим присвоением мы как бы "настраиваем" переменную-указатель p на то, чтобы она указывала на переменную a. Дальше идут две интересных строки с выводом на консоль, где мы вначале выводим содержимое самой переменной p, а после этого обращаемся к содержимому ячейки памяти, на которую указывает p посредством указания символа-звёздочки перед p, т.е. *p:
cout << "Pointer address is currently " << p << endl; // выводим значение указателя (это адрес памяти для переменной a)
cout << "Pointer value is currently " << *p << endl; // выводим значение "содержимого" по тому адресу памяти, который хранит сейчас p
Такая запись *p называется разыменованием указателя. Как вы уже, наверное, поняли, разыменование необходимо для того, чтобы обратиться к самим данным, на которые указывает в текущий момент времени переменная-указатель.
Оставшаяся часть программы делает аналогичную "перенастройку" переменной-указателя p на две другие переменные b и c и также выводит на экран консоли значения адресов этих переменных и значения самих переменных.
После запуска этой программы у меня на экране консоли отобразилось следующее:
The value of 'a' is: 10
The value of 'b' is: 20
The value of 'c' is: 30
Pointer address is currently 00CFF91C
Pointer value is currently 10
Pointer address is currently 00CFF910
Pointer value is currently 20
Pointer address is currently 00CFF904
Pointer value is currently 30
Обратите внимание, в моём случае адреса памяти для переменных a, b и c равны 00CFF91C, 00CFF910 и 00CFF904, соответственно (у вас они могут и скорее всего будут отличаться, это непринципиально). Также мы видим, что после каждой перенастройки переменной-указателя при разыменовании указателя p мы получаем доступ к самим значениям этих переменных, которые и выводятся на экран консоли.
Напоследок запомните следующие важные моменты про указатели в языке C++:
- Переменная-указатель всегда хранит адрес памяти, на который она указывает, а не сами данные.
- Для объявления переменной-указателя необходимо указать тип данных, на которые будет указывать указатель, затем символ-звёздочку ( * ) и после этого имя самой переменной. Например, чтобы объявить переменную-указатель с именем x на тип данных char, используется запись: char* x;
- Для разыменования указателя применяется символ-звёздочка ( * ), идущий перед именем переменной-указателя. Например, если ваша переменная-указатель имеет имя x, то её разыменование записывается как *x
- Для инициализации переменной-указателя используется ссылка ( с помощью & ) на какую-то объявленную переменную в Вашей программе. К примеру, если у вас уже была объявлена другая переменная с именем y, и её тип данных char, то можно проинициализировать указатель x следующим образом: x = &y;
- Не пытайтесь произвести разыменование переменной-указателя перед тем, как присвоите переменной корректное значение адреса какой-то объявленной переменной соответствующего типа.
Попробуйте выполнить следующие упражнения для закрепления темы указателей в языке C++:
- Объявите в своей программе три переменных x, y и z с типом double. Проинициализируйте их какими-то значениями на свой вкус. Также объявите три переменных-указателя с именами px, py, pz и проинициализируйте их таким образом, чтобы они указывали на x, y и z, соответственно. Выведите значения указателей px, py, pz (адреса памяти) на экран консоли. Также выведите на консоль значения самих переменных x, y и z с помощью доступа к ним через переменные-указатели px, py и pz и их разыменование. После этого присвойте указателю pz адрес переменной x, а указателю px присвойте адрес переменной z. Выведите на экран консоли результат разыменования для px и pz.