Введение в указатели C ++ и их приложения в программах на C ++

Обзор:

Вы только начали изучать программирование на C ++, понимаете основы и можете писать простые программы, но вы застряли на указателях C ++, потому что не понимаете, что это такое и как его использовать? Что ж, давайте исправим это, изучив основы указателей и их применение в программах на C ++.

Что такое указатель?

Первое, с чем нам нужно ознакомиться, это определение указателя.

указатель - это переменная, значение которой является физическим адресом другой переменной.

Подождите… физический адрес?

да. Физический адрес - это адрес в памяти, где в настоящее время хранится переменная. Выглядит это примерно так: 0x7fff5af67348. Не волнуйтесь, это просто числовое значение.

Так зачем мне указатель?

Указатели необходимы для более сложных структур данных, таких как массив или структура. Но мы забегаем вперед. Во-первых, мы должны узнать, как объявлять указатели, а также о некоторых специальных операторах, которые помогают нам использовать указатели. На ваш вопрос ответят по ходу дела.

Как объявить указатели?

Как и любая другая переменная в C ++, переменным-указателям также нужен определенный тип данных. Объявление указателей соответствует следующему синтаксису:

type * name;

Вот несколько примеров:

int * number;
char * character;
double * decimal;

Ну вы поняли.

Подождите, а что со звездочкой?

Звездочка - это унарный оператор, который требуется, чтобы сообщить компилятору, что объявляется переменная-указатель. Без него переменная представляет собой обычную переменную. Можно сказать, что без звездочки переменная не имеет смысла.

-_-

В любом случае, теперь мы знаем, как объявить указатель. Следующий шаг - узнать об операторах, которые делают указатели особенными. Они есть:

Оператор адресации (&) и Оператор разыменования (*)

Подождите, я видел их раньше.

Ну да, мы только что говорили о звездочке. Однако вариант использования этих операторов с указателями не влияет на их использование с другими операциями. А пока нам нужно понять, что они делают и как их использовать с указателями.

Что такое оператор адресации (&)?

Знак амперсанда (&), также известный как оператор адреса, используется для получения адреса переменной. Это можно сделать, поставив перед именем любой переменной, адрес которой нам нужен, с помощью (&). Если мы присвоим значение новой переменной, то новая переменная будет нашим указателем.

int * foo = &bar;

В приведенном выше примере мы назначаем адрес переменной bar переменной-указателю foo..

Хорошо, теперь это та часть, где вы должны были спросить, почему это полезно.

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

Я все больше запутываюсь.

Не волнуйся. Вы сбиты с толку, потому что обращаете внимание. Давайте снова посмотрим на приведенный выше пример, но со значением, присвоенным bar.

int bar = 2;
int * foo = &bar;

Здесь foo хранит адрес bar, который, вероятно, выглядит примерно как 0x7fff5af67348. Еще одна особенность указателей заключается в том, что они могут обращаться к значению, на которое указывает foo,, которое является фактическим значением bar. Мы можем сделать это с помощью нового оператора.

Что такое оператор разыменования (*)?

Знак звездочки (*), также известный как оператор разыменования, используется для получения значения, на которое указывает переменная. Это можно сделать, поставив перед именем переменной-указателя символ (*).

int baz = *foo;

Здесь baz теперь хранит значение, на которое указывает foo, которое является фактическим значением bar в первом примере. Это означает, что теперь значение baz равно 2.

Подождите, это не новый оператор. Это то, что мы использовали для объявления указателя.

Точное наблюдение. Звездочка, которую мы использовали для объявления указателя, совпадает с оператором разыменования. Тем не менее, вариант использования отличается, когда мы пытаемся разыменовать указатель на переменную. Это как омоним.

Хорошо ... Таким образом, указатель может хранить адрес другой переменной, а также может получать доступ к значению этой переменной.

Да, идеально. Теперь вы готовы к забавному примеру.

Интересный пример:

#include <iostream>
using namespace std;

int main() {
    int firstvalue, secondvalue;
    int * mypointer;
    
    mypointer = &firstvalue;
    *mypointer = 10;
    mypointer = &secondvalue;
    *mypointer = 20;
    
    cout << "firstvalue: " << firstvalue << "\n";
    cout << "secondvalue: " << secondvalue << "\n";
    
    return 0;
}

Итак, суть этой программы заключается в строках с 8 по 11. Рассмотрим каждую строку подробнее:

int baz = *foo;

Адрес целочисленной переменной firstvalue присваивается переменной-указателю mypointer.

*mypointer = 10;

Значению, на которое указывает mypointer, присваивается целочисленное значение 10.

Чего ждать?

Точно. До сих пор мы знали, что можем прочитать адрес и значение переменной через указатель с помощью оператора адреса и оператора разыменования соответственно. Однако оператор разыменования также можно использовать для записи и переназначения значений, на которые указывает указатель.

Но это не все…

mypointer = &secondvalue;

Здесь mypointer присваивается адрес новой переменной, secondvalue. Как и любой другой переменной в C ++, переменной-указателю также может быть присвоено новое значение, или в этом случае , адрес новой переменной. Переназначение дает mypointer контроль над вторым значением, что означает, что mypointer может получить доступ и переназначить второе значение. Это должно сделать строку 11 достаточно очевидной. Приведенная выше программа дает следующий результат.

first_value: 10
second_value: 20

В двух словах:

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