Save 37% off PRO during our Black Friday Sale! »

Программирование – 1 курс осень 2021 – 6 занятие

F21d69109b1c03921abf7d12f0fb6654?s=47 ТиМПИ
October 15, 2021

Программирование – 1 курс осень 2021 – 6 занятие

F21d69109b1c03921abf7d12f0fb6654?s=128

ТиМПИ

October 15, 2021
Tweet

Transcript

  1. 15 октября 2021 fvb@dscs.pro Федор Витальевич Бушмелев Указатели

  2. 2/52 2/52 Введение: пример 1 • Что: МатМех; • Хранится:

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

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

    Что: котик в коробке; • Хранится: кот 1шт; • Где: коробка №3.
  5. 5/52 5/52 А о чём вообще речь? Инициализация: Унарные операторы:

  6. 6/52 6/52 Адреса и разыменовывания • Оператор адреса (&) позволяет

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

    является адрес ячейки памяти.
  8. 8/52 8/52 Указатели 2/3

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

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

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

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

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

  14. 14/52 14/52 Нулевой указатель • Нулевое значение (или «значение null»)

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

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

    с помощью указателей. 2. Указатели – единственный способ динамического выделения памяти в C++. 3. Указатели могут использоваться для передачи большого количества данных в функцию без копирования этих данных. 4. Указатели могут использоваться для передачи одной функции в качестве параметра другой функции. 5. Указатели используются для достижения полиморфизма при работе с наследованием. 6. Указатели могут использоваться для представления одной структуры/класса в другой структуре/классе, формируя, таким образом, целые цепочки.
  17. 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; // количество байт, определенное типом
  18. 18/52 18/52 Указатели и функции 1/2

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

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

  21. 21/52 21/52 Ссылки • Ссылка — это (базовый) тип переменной

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

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

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

  25. 25/52 25/52 Константы Мудрость: Если есть ссылка или указатель на

    не константу, то с помощью нее можно проинициализировать ссылку или указатель на константу.
  26. 15 октября 2021 Никита Евгеньевич Ляпин Динамическая память

  27. 27/52 27/52 Типы выделения памяти • Статическое – память выделяется

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

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

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

    точек, размер которого заранее неизвестен. Возможное решение Можно задать массив некоторого фиксированного размера. Однако, очень часто он не будет заполнен до конца, из-за чего будет происходить потеря памяти.
  31. 31/52 31/52 Динамическая память Динамическое выделение памяти — способ запроса

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

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

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

    динамических переменных
  35. 35/52 35/52 Оператор new 3/3 • Динамические переменные не имеют

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

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

    a) b) c) d)
  38. 38/52 38/52 Динамические массивы 1/2 • В динамическом массиве, размер

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

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

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

  42. 42/52 42/52 Двумерные динамические массивы 1/3 Первый подход • Создаётся

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

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

    C++
  45. 45/52 45/52 Задание 5 Какая матрица будет выведена на экран

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

    n = 7?
  47. 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 - в противном случае.
  48. 48/52 48/52 Практическое задание (до 22.10.2021) 2/2 7. Написать функцию,

    заводящую верхне-треугольную матрицу заданного порядка (он определяется во время выполнения программы; хранить в памяти, естественно, нужно только возможно ненулевые элементы, заведомые нули ниже главной диагонали хранить незачем) в соответствии со вторым подходом к двумерным динамическим массивам (возвращает int**). Написать также функцию, выдающую ссылку на заданный элемент этой матрицы по указателю на такую матрицу (типа int**) и номерам строки и столбца (номера в исходной квадратной матрице; если соответствующий элемент лежит не ниже главной диагонали, нужно выдать ссылку на ту переменную в составе двумерного динамического массива, в которой этот элемент хранится, иначе выдается ссылка на локальную статическую переменную, которая обнуляется при каждом вызове этой функции). 8. Написать функцию, которая создаëт динамическую переменную, выводит на экран сообщение о «еë создании и типе» и возвращает указатель на неë. 9. Напишите функцию быстрой сортировки реализовав свою функцию swap(), аргументами последней будут переменные будут передаваться по ссылке. 10. Напишите функцию сортировки вставками, аргументом которой выступит собственная функция сравнения.
  49. 49/52 49/52 Домашнее задание (до 29.10.2021) 1/3 ЛЕГКО А) Динамически

    создайте структуру из указателей, пример которой изображен на рисунке: Б) При помощи указателей выведите значение, на которое они указывают. В) Перед завершением удалите все динамические объекты.
  50. 50/52 50/52 Домашнее задание (до 29.10.2021) 2/3 СРЕДНЕ Создайте динамический

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

    динамический массив указателей. Размер массива определяется путем ввода через консоль. Б) Написать функцию, при необходимости расширяющую этот динамический массив без пересоздания существующего, т.е. выделяется динамически еще один массив указателей размером определенном в пункте (а). Последний элемент (указатель) первого массива должен указывать на первый элемент второго массива указателей. В) Написать функцию, применяемую после каждого динамического выделения памяти и которая присваивает новый свободный указатель из массива на только что выделенную динамически память (если в нëм не хватает места, то необходимо расширить его функцией, описанной в пункте (б)). Г) Написать функцию, которая «слушает» консоль и в зависимости от ввода (продолжать или вершить выполнение программы) принимает динамический массив значений (вводится собственноручно). Д) Написать функцию, которая в конце программы проходится по массиву таких указателей и освобождает всю выделенную ранее память.
  52. 15 октября 2021 fvb@dscs.pro Федор Витальевич Бушмелев, Никита Евгеньевич Ляпин

    Указатели