Slide 1

Slide 1 text

15 октября 2021 [email protected] Федор Витальевич Бушмелев Указатели

Slide 2

Slide 2 text

2/52 2/52 Введение: пример 1 • Что: МатМех; • Хранится: 42; • Где: Университетский пр., 28.

Slide 3

Slide 3 text

3/52 3/52 Введение: пример 2 • Что: кастрюля; • Хранится: борщ; • Где: холодильник, 2 полка, справа белая кастрюля с цветами.

Slide 4

Slide 4 text

4/52 4/52 Введение: пример 3 3 2 1 0 • Что: котик в коробке; • Хранится: кот 1шт; • Где: коробка №3.

Slide 5

Slide 5 text

5/52 5/52 А о чём вообще речь? Инициализация: Унарные операторы:

Slide 6

Slide 6 text

6/52 6/52 Адреса и разыменовывания • Оператор адреса (&) позволяет узнать, какой адрес памяти присвоен определенной переменной. Возвращает указатель, а не литерал адреса! А адрес занимает объем памяти в зависимости от разрядности системы / исполняемого файла! • Оператор разыменования (*) позволяет получить значение по указанному адресу.

Slide 7

Slide 7 text

7/52 7/52 Указатели 1/3 Указатель — это переменная, значением которой является адрес ячейки памяти.

Slide 8

Slide 8 text

8/52 8/52 Указатели 2/3

Slide 9

Slide 9 text

9/52 9/52 Указатели 3/3

Slide 10

Slide 10 text

10/52 10/52 Частые ошибки с указателями 1/2

Slide 11

Slide 11 text

11/52 11/52 Частые ошибки с указателями 2/2

Slide 12

Slide 12 text

12/52 12/52 Задание 1

Slide 13

Slide 13 text

13/52 13/52 Задание 2

Slide 14

Slide 14 text

14/52 14/52 Нулевой указатель • Нулевое значение (или «значение null») — это специальное значение, которое означает, что указатель ни на что не указывает. • Указатель, содержащий значение null, называется нулевым указателем. • Разыменование нулевого указателя ведет себя также как и разыменование указателей с мусором приведет к неожиданным результатам (undefined behaviour). Скорей всего будет сбой/крах программы.

Slide 15

Slide 15 text

15/52 15/52 Указатели: краткие итоги 1/2 • Указатели — это переменные, которые содержат адреса памяти. • Используем оператор разыменования (*) для извлечения значений, хранимых по адресу памяти. • Разыменование указателя, значением которого является мусор, приведет к сбою в вашей программе. • При объявлении указателя указывайте звёздочку возле имени переменной.

Slide 16

Slide 16 text

16/52 16/52 Указатели: краткие итоги 2/2 Зачем? 1. Массивы реализованы с помощью указателей. 2. Указатели – единственный способ динамического выделения памяти в C++. 3. Указатели могут использоваться для передачи большого количества данных в функцию без копирования этих данных. 4. Указатели могут использоваться для передачи одной функции в качестве параметра другой функции. 5. Указатели используются для достижения полиморфизма при работе с наследованием. 6. Указатели могут использоваться для представления одной структуры/класса в другой структуре/классе, формируя, таким образом, целые цепочки.

Slide 17

Slide 17 text

17/52 17/52 Массивы и арифметика указателей Представление массивов: a[i] ~ *(a+i) ~ i[a]; int a[100]{}; Что выведет? a[150]; a[-5]; Арифметика указателей ➢ добавление константы: ptr++; ptr+3; // смещение влево по стеку на значение ➢ вычитание константы: --ptr; ptr-3; // смещение вправо по стеку на значение ➢ разница указателей: ptr1 – ptr2; // количество байт, определенное типом

Slide 18

Slide 18 text

18/52 18/52 Указатели и функции 1/2

Slide 19

Slide 19 text

19/52 19/52 Указатели и функции 2/2

Slide 20

Slide 20 text

20/52 20/52 Вопрос 1 Являлся ли Ленинград столицей Российской Империи?

Slide 21

Slide 21 text

21/52 21/52 Ссылки • Ссылка — это (базовый) тип переменной в языке C++, который работает как псевдоним другого объекта или значения. • «Под капотом» ссылки и указатели работают идентично, т.е. ссылки реализованы через указатели.

Slide 22

Slide 22 text

22/52 22/52 Ссылки как параметр функции

Slide 23

Slide 23 text

23/52 23/52 Ссылки делают «жизнь» проще

Slide 24

Slide 24 text

24/52 24/52 Ссылки делают «жизнь» сложнее

Slide 25

Slide 25 text

25/52 25/52 Константы Мудрость: Если есть ссылка или указатель на не константу, то с помощью нее можно проинициализировать ссылку или указатель на константу.

Slide 26

Slide 26 text

15 октября 2021 Никита Евгеньевич Ляпин Динамическая память

Slide 27

Slide 27 text

27/52 27/52 Типы выделения памяти • Статическое – память выделяется ровно один раз во время запуска программы и сохраняется на протяжении всей работы программы. Выполняется для глобальных и статических переменных. • Автоматическое – память выделяется при входе в блок, содержащий данные переменные, и удаляется при выходе из него. Выполняется для локальных переменных и параметров функций. Статическое выделение памяти Автоматическое выделение памяти

Slide 28

Slide 28 text

28/52 28/52 Сопутствующие проблемы 1/3 • Выделение и освобождение памяти происходит в тот момент, когда переменная создается в подпрограмме или, соответственно, уничтожается. • Их размер должен быть известен заранее, во время компиляции. Локальная переменная – непостоянный друг

Slide 29

Slide 29 text

29/52 29/52 Сопутствующие проблемы 2/3 Проблема №1 Что делать в случае, когда в подпрограмме необходимо завести переменную, которая сохраняется и при выходе из подпрограммы? Возможное решение Можно воспользоваться статическими переменными, если количество таких переменных известно заранее. Но крайне часто это не так.

Slide 30

Slide 30 text

30/52 30/52 Сопутствующие проблемы 3/3 Проблема №2 Требуется задать массив точек, размер которого заранее неизвестен. Возможное решение Можно задать массив некоторого фиксированного размера. Однако, очень часто он не будет заполнен до конца, из-за чего будет происходить потеря памяти.

Slide 31

Slide 31 text

31/52 31/52 Динамическая память Динамическое выделение памяти — способ запроса памяти подпрограммами из специального хранилища операционной системы по мере необходимости. Операторы new и delete (выделения и освобождения памяти)

Slide 32

Slide 32 text

32/52 32/52 Особенности • При динамическом выделении память берётся из кучи. • Освобождать занимаемую переменными память можно в любом порядке (в отличие от локальных переменных из стека). • Выделение и освобождение памяти в куче происходит намного медленнее, чем в стеке. Разница между стеком и кучей

Slide 33

Slide 33 text

33/52 33/52 Оператор new 1/3 • Оператор new – оператор обеспечивающий выделение динамической памяти в куче. int* p = new int; Тип указателя на переменную Имя указателя Оператор new Тип динамической переменной

Slide 34

Slide 34 text

34/52 34/52 Оператор new 2/3 Пример использования new для инициализации динамических переменных

Slide 35

Slide 35 text

35/52 35/52 Оператор new 3/3 • Динамические переменные не имеют имён, доступ к ним возможен только через указатели на них. • Утечка памяти – ситуация, при которой в результате ошибок в программе возникают динамические переменные, на которые никакой указатель не указывает. • Мусор – недоступные динамические переменные. Пример утечки памяти

Slide 36

Slide 36 text

36/52 36/52 Оператор delete • Оператор delete – оператор освобождения памяти, выделенной оператором new. • Динамические переменные, которые перестали использоваться надо удалять вручную вызовом delete. (в C#, например, есть так называемый «сборщик мусора») // Возвращаем память, на которую указывал p, обратно в операционную систему delete p; Оператор Имя указателя

Slide 37

Slide 37 text

37/52 37/52 Задание 3 В каких вариантах имеется утечка памяти? a) b) c) d)

Slide 38

Slide 38 text

38/52 38/52 Динамические массивы 1/2 • В динамическом массиве, размер не определён заранее и может быть задан пользователем или любым выражением, возвращающим целое число. • Операторы new и delete для динамических массивов имеют следующий вид: Операторы new и delete

Slide 39

Slide 39 text

39/52 39/52 Динамические массивы 2/2 • Отсутствует встроенный способ изменения длины массива, который уже был выделен. • Можно обойти это ограничение, динамически выделив новый массив, скопировав все элементы из старого массива, а затем удалив старый массив (однако этот способ подвержен ошибкам). • Можно использовать шаблонный класс vector, который позволяет менять свой размер в любой момент программы. 1 2 … n p 1 2 3 … p n + m Изменение длины динамического массива

Slide 40

Slide 40 text

40/52 40/52 Задание 4 Что плохого в данном коде?

Slide 41

Slide 41 text

41/52 41/52 Вопрос 2 Где используются двумерные массивы?

Slide 42

Slide 42 text

42/52 42/52 Двумерные динамические массивы 1/3 Первый подход • Создаётся одномерный динамический массив, длина которого равна количеству необходимых элементов. • При обращении пара индексов в двумерном массиве пересчитывается в один индекс в одномерном. Реализация первого подхода на C++

Slide 43

Slide 43 text

43/52 43/52 Двумерные динамические массивы 2/3 Второй подход • Привычный синтаксис доступа к элементам массива. • Сложнее в реализации по сравнению с первым подходом. • Позволяет задавать строки разной длины, что удобно для хранения разреженных матриц. Реализация второго подхода

Slide 44

Slide 44 text

44/52 44/52 Двумерные динамические массивы 3/3 Реализация второго подхода на C++

Slide 45

Slide 45 text

45/52 45/52 Задание 5 Какая матрица будет выведена на экран при m = 6, n = 5?

Slide 46

Slide 46 text

46/52 46/52 Задание 6 Что будет выведено на экран при n = 7?

Slide 47

Slide 47 text

47/52 47/52 Практическое задание (до 22.10.2021) 1/2 1. Использовать указатель в качестве итератора при прохождении по массиву/строке. 2. Объявить последовательно переменные типов int, char, bool, short, long, float, double, long double, int[]. Вывести их адреса; сравнить разности адресов с размерами переменных и внутри массива int[], выдаваемыми операцией sizeof(). 3. Написать функции для создания двумерного динамического массива, заполнения его случайными числами от 0 до 100 (с помощью функций srand() и rand()) и печати его содержимого на экран. 4. Объявите динамический массив символов, размер которого вводится пользователем. Самостоятельно заполните его. Посмотрите на адреса каждого элемента с помощью оператора &. Какую закономерность можно наблюдать? 5. Объявите динамический массив чисел, размер которого вводится пользователем. Самостоятельно заполните его. С помощью арифметики указателей выведите на экран его содержимое в обратном порядке. 6. Написать функцию, которая сравнивает два указателя и возвращает 1, если они указывают на один и тот же участок памяти, и 0 - в противном случае.

Slide 48

Slide 48 text

48/52 48/52 Практическое задание (до 22.10.2021) 2/2 7. Написать функцию, заводящую верхне-треугольную матрицу заданного порядка (он определяется во время выполнения программы; хранить в памяти, естественно, нужно только возможно ненулевые элементы, заведомые нули ниже главной диагонали хранить незачем) в соответствии со вторым подходом к двумерным динамическим массивам (возвращает int**). Написать также функцию, выдающую ссылку на заданный элемент этой матрицы по указателю на такую матрицу (типа int**) и номерам строки и столбца (номера в исходной квадратной матрице; если соответствующий элемент лежит не ниже главной диагонали, нужно выдать ссылку на ту переменную в составе двумерного динамического массива, в которой этот элемент хранится, иначе выдается ссылка на локальную статическую переменную, которая обнуляется при каждом вызове этой функции). 8. Написать функцию, которая создаëт динамическую переменную, выводит на экран сообщение о «еë создании и типе» и возвращает указатель на неë. 9. Напишите функцию быстрой сортировки реализовав свою функцию swap(), аргументами последней будут переменные будут передаваться по ссылке. 10. Напишите функцию сортировки вставками, аргументом которой выступит собственная функция сравнения.

Slide 49

Slide 49 text

49/52 49/52 Домашнее задание (до 29.10.2021) 1/3 ЛЕГКО А) Динамически создайте структуру из указателей, пример которой изображен на рисунке: Б) При помощи указателей выведите значение, на которое они указывают. В) Перед завершением удалите все динамические объекты.

Slide 50

Slide 50 text

50/52 50/52 Домашнее задание (до 29.10.2021) 2/3 СРЕДНЕ Создайте динамический двумерный массив и заполните его случайными числами от 10 до 50. Выведите его в консоль. Для наполнения и визуализации необходимо написать отдельные функции. На вход функции получают: • указатель на динамический массив; • количество строк; • количество столбцов. Количество строк и столбцов, вводятся пользователем через консоль.

Slide 51

Slide 51 text

51/52 51/52 Домашнее задание (до 29.10.2021) 3/3 СЛОЖНО А) Создать динамический массив указателей. Размер массива определяется путем ввода через консоль. Б) Написать функцию, при необходимости расширяющую этот динамический массив без пересоздания существующего, т.е. выделяется динамически еще один массив указателей размером определенном в пункте (а). Последний элемент (указатель) первого массива должен указывать на первый элемент второго массива указателей. В) Написать функцию, применяемую после каждого динамического выделения памяти и которая присваивает новый свободный указатель из массива на только что выделенную динамически память (если в нëм не хватает места, то необходимо расширить его функцией, описанной в пункте (б)). Г) Написать функцию, которая «слушает» консоль и в зависимости от ввода (продолжать или вершить выполнение программы) принимает динамический массив значений (вводится собственноручно). Д) Написать функцию, которая в конце программы проходится по массиву таких указателей и освобождает всю выделенную ранее память.

Slide 52

Slide 52 text

15 октября 2021 [email protected] Федор Витальевич Бушмелев, Никита Евгеньевич Ляпин Указатели