Slide 1

Slide 1 text

22 октября 2021 [email protected] Анастасия Андреевна Корепанова Стек вызовов

Slide 2

Slide 2 text

2/38 2/38 Порядок выполнения main() bar(a, b, c) foo(a, b, c)

Slide 3

Slide 3 text

3/38 3/38 Память программы Источник: https://learnc.info/c/program_structure.html Область памяти для глобальных и статических переменных Область динамической памяти (куча) Стек вызовов Область кода

Slide 4

Slide 4 text

4/38 4/38 Стек 1/2 • При запуске программы (процесса) операционная система выделяет ей область в оперативной памяти. В этой области среди прочего располагается стек. • Стек вызовов — это структура, хранящая локальную информацию исполняемой функции, а также информацию для возврата управления из подпрограмм (функций) в программу или подпрограмму. • LIFO — «last in first out». • Максимальный размер стека всегда ограничен. Может быть 4 Мб (для Windows обычно 1 МБ). данные функции 1 данные функции 2 данные функции 3 данные функции 4 данные функции 5 данные функции 6

Slide 5

Slide 5 text

5/38 5/38 Стек 2/2 Вот почему очень важно инициализировать переменные! Данные функции 1 Данные функции 2 Данные функции 1 Данные функции 2 Данные функции 1 Данные функции 2 Данные функции 3 x = 4 str = “Слава СССР” bin = true … Призрак функции 3 x = 4 str = “Слава СССР bin = true … Данные функции 4 y = 4 b = “Слава СССР” d = true …

Slide 6

Slide 6 text

6/38 6/38 Кадр стека • Данные одной функции лежат в одном кадре стека (stack frame) • В одном кадре стека содержатся локальные переменные функции, значения регистров процессора, которые надо будет восстановить после выполнения следующей вызываемой функции, адрес инструкции, которая будет выполнена после возврата из функции, резервируется место для возвращаемого значения вызываемой функции, промежуточные значения при вычислении сложных выражений тоже хранятся на стеке • На самом деле, всё зависит от конкретной архитектуры, но примерно так реализовано Локальные переменные функции Аргументы вызова следующей функции Место возвращаемого значения следующей функции Адрес возврата Регистры процессора Frame pointer Stack pointer Локальные переменные функции Frame pointer Stack pointer

Slide 7

Slide 7 text

7/38 7/38 Кадр стека: пример

Slide 8

Slide 8 text

8/38 8/38 Уязвимости 1/2 • Переполнение стека (stack overflow) Стек очень ограничен в объёме, при вызове слишком большого числа вложеннных функций / инициализации слишком большого числа переменных стек может переполниться Причины возникновения: 1. Бесконечная рекурсия 2. Очень глубокая рекурсия 3. Очень большие переменные

Slide 9

Slide 9 text

9/38 9/38 Уязвимости 2/2 • Переполнение буффера (buffer overflow) Функции начинают писать и обращаться не к своим кадрам стека. Данные функции 1 Данные функции 2 Данные функции 3 x = 4 str = “Слава СССР” bin = true …

Slide 10

Slide 10 text

10/38 10/38 Код, который не вызывает stackoverflow

Slide 11

Slide 11 text

11/38 11/38 Рекурсия и хвостовая рекурсия • Рекурсивная функция – это функция, которая вызывает сама себя. • Хвостовая рекурсия – рекурсия, в которой последней операцией перед выходом из функции является рекурсивный вызов. • Давайте напишем факториал!

Slide 12

Slide 12 text

12/38 12/38 Ещё раз про память программы Источник: https://learnc.info/c/program_structure.html Область памяти для глобальных и статических переменных Область динамической памяти (куча) Стек вызовов Область кода Не так всё просто!!!

Slide 13

Slide 13 text

22 октября 2021 [email protected] Анастасия Андреевна Корепанова Библиотека ввода и вывода

Slide 14

Slide 14 text

14/38 14/38 План занятия 1. Кодировки 2. Работа со строками 3. Ввод и вывод 4. Понятие файла

Slide 15

Slide 15 text

15/38 15/38 Кодировки: зачем?

Slide 16

Slide 16 text

16/38 16/38 Кодировки • ASCII, UTF-8 и т.д. • Char, wchar_t, char16_t и char32_t • В начале файла может быть BOM • А как понять, какая кодировка? Количество октетов Значащих бит Шаблон 1 7 0xxxxxxx 2 11 110xxxxx 10xxxxxx 3 16 1110xxxx 10xxxxxx 10xxxxxx 4 36 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

Slide 17

Slide 17 text

17/38 17/38 Строки • Строки — массивы символов типа char, заканчивающиеся нулевым символом. • Строки могут содержать управляющие последовательности: 1. \n — перевод строки, 2. \t — символ табуляции, 3. \\ — символ «\», 4. \” — символ «”» 5. \0 — завершающий строку символ. Экранирование служебных символов * Вспомним: что такое массивы?

Slide 18

Slide 18 text

18/38 18/38 Инициализация строк

Slide 19

Slide 19 text

19/38 19/38 Вопрос 1 Вывод: ??? 1. \n — перевод строки, 2. \t — символ табуляции, 3. \\ — символ «\», 4. \” — символ «”» 5. \0 — нулевой символ.

Slide 20

Slide 20 text

20/38 20/38 Ответ 1 Вывод: He____ll 1. \n — перевод строки, 2. \t — символ табуляции, 3. \\ — символ «\», 4. \” — символ «”» 5. \0 — нулевой символ.

Slide 21

Slide 21 text

21/38 21/38 Работа со строками в стиле C • Библиотека cstring предлагает множество функций для работы со строками. Под строками в данной библиотеке подразумеваются указатели типа char (char *)

Slide 22

Slide 22 text

22/38 22/38 Работа со строками в стиле C++ • Библиотека string предлагает обёртку над строками, которая позволяет упростить все операции со строками.

Slide 23

Slide 23 text

23/38 23/38 Вопрос 2 Вывод: ??? 1. \n — перевод строки, 2. \t — символ табуляции, 3. \\ — символ «\», 4. \” — символ «”» 5. \0 — нулевой символ.

Slide 24

Slide 24 text

24/38 24/38 Ответ 2 Вывод: He____ll 4 1. \n — перевод строки, 2. \t — символ табуляции, 3. \\ — символ «\», 4. \” — символ «”» 5. \0 — нулевой символ.

Slide 25

Slide 25 text

25/38 25/38 String vs Cstring • Cstring позволяет экономить память. • Требует больше внимательности. • Следует использовать, есть очень жёсткие требования по памяти, а также если придётся работать с C библиотеками, которые требуют такой формат ввода. • String более удобна. • Выделение/высвобождение динамической памяти может вести к дефрагментации памяти. • В целом требует больше ресурсов. • Следует использовать во всех остальных случаях.

Slide 26

Slide 26 text

26/38 26/38 Потоки ввода и вывода • Поток (англ. stream) – это абстракция, используемая для чтения и записи файлов, сокетов и т.п. в единой манере. Потенциально бесконечная последовательность данных, к которым можно получать последовательный доступ.

Slide 27

Slide 27 text

27/38 27/38 Ввод и вывод в стиле C • Библиотека cstdio Почему может быть небезопасно?

Slide 28

Slide 28 text

28/38 28/38 Ввод и вывод в стиле C++ 1/2 • Библиотека Плюсы: 1. Типобезопасна. 2. Гораздо более удобна ☺. 3. Есть строковые потоки. 4. Можно писать вывод для своих структур и классов.

Slide 29

Slide 29 text

29/38 29/38 Ввод и вывод в стиле C++ 2/2 • : • istream, wistream — читают данные из потока. • ostream, wostream — записывают данные в поток. • iostream, wiostream — читают и записывают данные в поток. • : • ifstream, wifstream — читают данные из файла. • ofstream, wofstream — записывают данные в файл. • fstream, wfstream — читают и записывают данные в файл. • • istringstream, wistringstream — читают данные из строки. • ostringstream, wostringstream — записывают данные в строку. • stringstream, wstringstream — читают и записывают данные в строку.

Slide 30

Slide 30 text

30/38 30/38 Методы класса iostream operator>> Оператор извлечения данных. Игнорирует все пробелы, символы табуляции и символ новой строки get Извлекает символ из входного потока. Не считывает символ новой строки getline Извлекает символ из входного потока. peek Подсматривает следующий символ в потоке putback Кладет последний считанный символ обратно

Slide 31

Slide 31 text

31/38 31/38 Буфер • Каждый объект ввода-вывода управляет буфером, используемым для хранения данных, которые программа читает или записывает. • Использование буфера позволяет операционной системе объединить несколько операций вывода данной программы. • Запись в устройство медленное, возможность операционной системы объединить несколько операций вывода в одну способствует повышению производительности.

Slide 32

Slide 32 text

32/38 32/38 Сброс буфера • Программа завершается нормально. Все буфера вывода освобождаются при выходе из функции main (). • В некий случайный момент времени буфер может оказаться заполненным. В этом случае перед записью следующего значения происходит сброс буфера. • Сброс буфера можно осуществить явно, использовав такой манипулятор, как endl. • Используя манипулятор unitbuf, можно установить такое внутреннее состояние потока, чтобы буфер освобождался после каждой операции вывода. Для объекта cerr манипулятор unitbuf установлен по умолчанию, поэтому запись в него приводит к немедленному выводу.

Slide 33

Slide 33 text

33/38 33/38 Внимание • Буфер вывода не сбрасывается, если программа завершается аварийно. • При попытке отладить аварийно завершающуюся программу необходимо гарантировать, что любой подозрительный вывод будет сброшен сразу.

Slide 34

Slide 34 text

34/38 34/38 Ввод и вывод в файл fstream fstrm Создает несвязанный файловый поток, fst ream — это один из типов, определенных в заголовке fstream fstream fstrm(s) Создает объект класса fstream и открывает файл по имени s. fstream fstrm (s, режим) Подобен предыдущему конструктору, но открывает файл s в указанном режиме fstrm.open (s) fstrm.open (s, режим) Открывает файл s и связывает его с потоком fstrm. fstrm.close() Закрывает файл, с которым связан поток fstrm. fstrm.is_open () Возвращает значение типа bool, указывающее, был ли cвязанный с потоком fstrm файл успешно открыт и не был ли он закрыт

Slide 35

Slide 35 text

35/38 35/38 Класс std::ios_base Константа Описание ios_base::in открыть файл для чтения ios_base::out открыть файл для записи ios_base::ate при открытии переместить указатель в конец файла ios_base::app открыть файл для записи в конец файла ios_base::trunc удалить содержимое файла, если он существует ios_base::binary открытие файла в двоичном режиме

Slide 36

Slide 36 text

36/38 36/38 Резюме Язык C++ использует библиотечные классы для обработки потоков ввода и вывода. • Класс iоstrеam отрабатывает ввод-вывод на консоль. • Класс fstream отрабатывает ввод-вывод в именованным файл. • Класс stringstream отрабатывает ввод-вывод в строки в оперативной памяти. Классы fstream и stringstream связаны происхождением от класса iostream. Классы ввода происходят от класса istream, а классы вывода— от класса ostгearn. Таким образом, операции, которые могут быть выполнены с объектом класса istream, могут быть также выполнены с объектом класса ifstream или istringstream. Аналогично для классов вывода, происходящих от класса ostream.

Slide 37

Slide 37 text

37/38 37/38 Задачи на практику • Написать вычисление чисел Фибоначчи с помощью рекурсии и без неё. • Попробовать уронить программу с помощью переполнения стека. • Ввести строку и заменить все встречающиеся в ней суммы натуральных чисел на их результаты. Например, при вводе 5+26-72+35gh32+45. Результат должен быть 31-107gh77. • Написать программу, которая из файла получает строку с математическим выражением и разбивает ее на обратную польскую запись и выводит в файл следующей строкой. • Ввести строку и после каждого вхождения в нее подстроки «password:» заменить восемь следующих символов на звездочки.

Slide 38

Slide 38 text

22 октября 2021 [email protected] Анастасия Андреевна Корепанова Стек вызовов