-
Notifications
You must be signed in to change notification settings - Fork 27
Expand file tree
/
Copy path08_pointers.cpp
More file actions
114 lines (84 loc) · 6.63 KB
/
08_pointers.cpp
File metadata and controls
114 lines (84 loc) · 6.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include <iostream> // cout, printf
int main() {
// 1. Память и адреса.
// При "объявлении" переменной под нее автоматически выделяется
// свободный участок памяти (RAM), размер которого зависит от типа переменной.
// Например, под тип int выделится 4 или 8 байтов (зависит от компилятора).
int a = 7; // 4 байта под хранение числа 7
int b = 11; // 4 байта под хранение числа 11
std::cout << "a = " << a << '\n';
std::cout << "b = " << b << '\n';
// 2. Понятие указателя.
// В C++ можно получить адрес на участок памяти, в которой хранится переменная.
// Для этого используется оператор взятия адреса & (амперсанд).
int* pointer_to_a = &a; // адрес в памяти, т.е. указатель на переменную типа int
// Заметка 1: адрес переменной 'a' хранится в новой переменной под названием 'pointer_to_a'.
/*
* Пояснения:
* 1. int * - читаем справа налево: указатель * на переменную типа int => * на int.
* 2. Указатель - это переменная, которая хранит в себе адрес на определенный участок памяти.
* 3. Адрес - это некое число, номер ячейки в памяти (обычно представляемое в 16-ой СС).
* 4. Тип указателя должен соответствовать типу переменной, на которую он указывает!
*/
/*
* Повторение - мать ... твою!
* Под переменную выделяется участок памяти, у которой есть адрес (адрес = число).
* Адрес переменной можно получить, используя оператор взятия адреса & (амперсанд).
* Указатель - это новая переменная со значением адреса другой переменной.
*/
// Выведем адрес переменных 'a' и 'b' в стандартный поток вывода stdout.
printf("&a = %X\n", pointer_to_a); // %X - вывода значения в 16-ой СС
printf("&b = %X\n", &b);
// 3. Чтение данных по указателю.
// Замечательно, у нас есть адрес на участок памяти, где хранится значение переменной 'a'.
// Для получения доступа к данным по указателю используется оператор разыменования * (звездочка).
// Создадим новую переменную 'c' и скопируем туда значение переменной 'a'.
int c = *pointer_to_a; // копируем в 'c' значение переменной, на которую ссылается указатель
/*
* Пояснения (rolling in the deep ... shit):
* 1. pointer_to_a - переменная, которая хранит в себе адрес 'a'
* 2. адрес нам не нужен, мы хотим получить значение, которое хранится в 'a'
* 3. используем оператор * для "перехода" по адресу 'a' (тук-тук, 'a', выходи)
* 4. 'a' "вышел" и дал нам увидеть свое лицо (хранимое значение)
* 5. сохраняем (копируем) значение 'a' в переменную 'c', используя оператор =
*/
std::printf("c = %d\n", c); // значение переменной равно значению 'a'
std::printf("&c = %X\n", &c); // адрес не совпадает с адресом 'a'
// 4. Запись данных по указателю.
// Изменим значение переменной 'a' по указателю.
*pointer_to_a = 3;
/*
* Пояснения:
* 1. pointer_to_a - переменная, которая хранит адрес 'a'
* 2. при помощи оператора * "переходим" по адресу на участок памяти 'a'
* 3. записываем в этот участок памяти новое значение, используя оператор =
*/
std::printf("a = %d\n", a); // значение переменной изменилось
std::printf("&a = %X\n", &a); // адрес не изменился
// 5. Указатель, который никуда не ссылается.
// В С++ есть ключевое слово nullptr, которое обозначает, что указатель никуда не ссылается.
int* null_pointer = nullptr; // Python: None, Java: null
// nullptr всегда ссылается на "несуществующий" участок в памяти, т.е. ноль
std::printf("nullptr = %X\n", null_pointer);
// 6. Проверка и сравнение указателей.
// Проверка указателя на то, что он ссылается на "существующий" участок в памяти.
if (pointer_to_a != nullptr) {
std::cout << "Pointer 'a' is not nullptr\n";
}
// На один и тот же участок памяти можно создать несколько указателей.
int* pointer_to_a_1 = &a;
int* pointer_to_a_2 = &a;
// Проверим, ссылаются ли они на один и тот же участок в памяти.
if (pointer_to_a_1 == pointer_to_a_2) {
std::cout << "pointers are equal\n";
}
// 7. Будьте бдительны!
int* bad_pointer; // хранит в себе адрес на "мусорный" участок памяти (непонятно куда указывает)
return 0;
}
/*
* Задания:
* 1. Для чего используется указатели? В чем заключается проблема использования переменных в простом виде?
* 2. Можно ли указателем сослаться на "запрещенный" участок памяти?
* 3. Реализуйте операцию swap - поменять местами значения переменных.
*/