1.60M
Категория: ПрограммированиеПрограммирование

Информационные технологии. Часть 2. Тема 8. Указатели и массивы. Динамические массивы

1.

Санкт-Петербургский государственный
архитектурно-строительный университет
кафедра информационных технологий
Информационные технологии. Часть 2
Тема 8
Указатели и массивы. Динамические массивы
Букунов Сергей Витальевич
к.т.н., доцент, доцент

2.

РАБОТА С МАССИВАМИ
ЧЕРЕЗ УКАЗАТЕЛИ

3.

Основные сведения
Имя массива представляет собой его адрес (адрес первого элемента
массива).
Этот адрес можно записать в указатель.
Таким образом, для доступа к элементам массива можно
использовать как индекс элемента, так и указатель.
Для правильной организации приращения адреса при
перемещениях по массиву при объявлении указателя необходимо
указывать тип данных, которые будут храниться в массиве (int*,
double* и т.д.).

4.

Доступ к элементам массива через указатели

5.

Передача массива в функцию через указатель
Работа с функциями в случае использования указателей строится
по следующей схеме:
в качестве аргумента функции используется указатель;
при вызове функции в качестве аргумента задается имя массива.

6.

Передача одномерного массива в функцию по указателю

7.

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

8.

Передача двумерного массива в функцию через указатель
Для передачи в функцию двумерного массива размерностью n × m
в качестве аргумента ей необходимо передать не просто указатель,
а указатель на массив, каждый элемент которого состоит из m
элементов, где m – количество элементов в каждой строке массива
(т.е. количество столбцов).
Синтаксис такого указателя следующий:
int (*ptr) [m];
Для доступа к элементам массива в этом случае используется
обычный синтаксис массива, т.е. указатель трактуется как имя
массива.

9.

Передача двумерного массива в функцию по указателю

10.

Передача двумерного массива в функцию по указателю

11.

ВЫДЕЛЕНИЕ
ДИНАМИЧЕСКОЙ
ПАМЯТИ

12.

Выделение динамической памяти. Операция new
Чаще всего указатели используются для выделения динамической
памяти во время выполнения программы.
Для этого используется ключевая операция new.
Алгоритм выделения динамической памяти следующий:
Вы сообщаете оператору new, для какого типа данных
запрашивается память;
операционная система находит блок памяти нужного размера и
возвращает его адрес;
этот адрес записывается в указатель.

13.

Выделение динамической памяти. Операция new
Общая форма выделения памяти для отдельного объекта данных:
TYPE* pointer = new TYPE; // выделение памяти под один
элемент типа TYPE;
TYPE* pointer = new TYPE [n] // выделение области памяти для
массива из n элементов типа TYPE и присваивание адреса
выделенной области памяти указателю pointer.

14.

Выделение динамической памяти. Операция new

15.

Особенности работы с динамической памятью
В виду того, что память компьютера является ограниченным
ресурсом, попытка выделения памяти с помощью операции new
может оказаться неудачной. В этом случае операция new
генерирует исключение (возвращает значение 0).
В С++ указатель со значением 0 называется NULL-указателем (или
нулевым указателем).
С++ гарантирует, что нулевой указатель никогда не указывает на
допустимые данные, поэтому он часто используется в качестве
признака неудачного завершения операций или функций, которые в
противном случае должны возвращать корректные указатели.

16.

Освобождение динамической памяти. Операция delete
Когда память, выделенная под переменную, больше не нужна, ее
следует освободить для осуществления возможности ее повторного
использования другими частями программы.
Для освобождения выделенной памяти применяется операция
delete.
Общая форма освобождения выделенному отдельному объекту
данных памяти выглядит следующим образом:
delete pointer; // освобождение области памяти, занятую одной
переменной, адрес которой хранится в указателе pointer
delete [ ] pointer; // освобождение области памяти, занятую
массивом, адрес которого хранится в указателе pointer

17.

Освобождение динамической памяти. Операция delete
Если не освободить выделенную динамическую память, например,
после выхода из функции, в которой она была выделена, то эта
память остается зарезервированной, несмотря на то, что она
больше не используется (т.к. мы вышли из функции).
Такой эффект часто называют «утечкой памяти».
В некоторых языках программирования, например, в языке Python,
есть специальные системные утилиты, называемые «сборщиками
мусора», которые выявляют такую зарезервированную, но
неиспользуемую память, и автоматически освобождают её.
В языке С++ таких утилит нет, поэтому за освобождением
динамической памяти должен следить сам программист.

18.

Особенности работы с динамической памятью
При использовании операций new и delete необходимо придерживаться
следующих правил:
операция delete используется только с памятью, выделенной
операцией new;
нельзя использовать операцию delete дважды для освобождения
одного и того же блока памяти;
нельзя использовать операцию [ ] delete для освобождения блока
памяти, выделенного с помощью операции new для одного элемента;
нельзя использовать операцию delete для освобождения блока памяти,
выделенного с помощью операции new для массива элементов;
применение операции delete к нулевому указателю является
безопасным.

19.

Примеры некорректного использования операции delete
int* ps = new int; // корректно
delete ps;
// корректно
delete ps;
// некорректно – нельзя пытаться освободить дважды одну и ту же область памяти
int var = 5; // корректно
int* pi = &var; // корректно
delete pi; // некорректно – память, на которую указывает pi, не была выделена с помощью
операции new
int* ps = new int; // корректно
int* pq = ps;
// корректно
delete pq; // корректно – pq и ps указывают на один и тот же блок памяти, выделенный с
помощью операции new
int* pt = new int; // корректно
delete [ ] pt; // некорректно – эффект не определен; память была выделена под один элемент
типа int
short* ps = new short[500]; // корректно
delete ps; // некорректно – эффект не определен; память была выделена под массив элементов
типа short

20.

ДИНАМИЧЕСКИЕ
МАССИВЫ

21.

Одномерный динамический массив
Для создания одномерного динамического массива достаточно
сообщить операции new тип элементов массива и требуемое
количество элементов.
Пример. Выделение динамической памяти для хранения массива из
10 элементов типа int:
int* pi = new int [10];
Операция new возвращает адрес первого элемента в блоке,
значение которого присваивается указателю pi.
Здесь указатель pi указывает на первый элемент выделенного
массива.
По завершению работы с выделенным блоком памяти необходимо
сбалансировать вызов new соответствующим вызовом delete:
delete [ ] pi;

22.

Примеры работы с динамической памятью

23.

Примеры работы с динамической памятью
Вопрос: в чем ошибка ?

24.

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

25.

Примеры работы с динамической памятью

26.

Многомерные динамические массивы
Для создания многомерных (например, двумерных) динамических
массивов воспользоваться оператором
int** masd = new int [n] [k];
по аналогии с одномерным динамическим массивом нельзя, т.к. в
этом случае возникает ошибка несоответствия указателей.

27.

Двумерный динамический массив
Динамический двумерный массив размерностью m × n создается
следующим образом:
1.
Сначала необходимо с помощью операции new выделить
память под массив из m указателей (для m строк). Эта память будет
представлять собой массив (или вектор), элементами которого
будут
являться
указатели,
располагающиеся
в
памяти
последовательно.
2.
После этого необходимо в цикле каждому указателю
присвоить адрес выделенной области памяти размером n, равным
границе массива, т.е. количеству столбцов.

28.

Двумерный динамический массив
Динамический двумерный массив существенно отличается от
обычного двумерного массива.
Под обычный двумерный массив при объявлении выделяется
сплошной участок памяти.
Для динамического массива выделенная память не представляет
собой сплошной участок, поскольку она выделяется с помощью
нескольких операций new.

29.

Реализация двумерного динамического массива

30.

Реализация двумерного динамического массива

31.

РАБОТА СО СТРОКАМИ
ЧЕРЕЗ УКАЗАТЕЛИ

32.

Строки как массивы
Строки – это массивы элементов типа char.
Поэтому доступ к элементам строки аналогичен доступу к
элементам массива.
Однако при работе со строками следует иметь в виду тот факт,
функциональность работы со строками зависит от способа
определения самой строки.

33.

Строки как массивы
Вопрос: существует ли принципиальное отличие между этими
двумя способами определения строки с точки зрения вывода?

34.

Строки как массивы
Ответ: с точки зрения вывода отличий нет.

35.

Строки как массивы
Вопрос: существует ли принципиальное отличие между этими
двумя способами определения строки с точки зрения посимвольной
работы со строкой?
Какой из операторов компилятор не пропустит и почему?
str1++;
str2++;

36.

Строки как массивы
Ответ:
str1 - это имя массива, которое представляет собой по факту
константный указатель, поэтому изменять значение указателя
нельзя;
str2 – это указатель на константу, поэтому значение самого
указателя можно изменять.

37.

Строки как массивы
Вопрос: что мы увидим на экране ?

38.

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

39.

Строки как массивы
Вопрос: Пропустит ли компилятор такой код и что мы увидим на
экране в этом случае ?

40.

Строки как массивы
Ответ:

41.

Строки как массивы
Вопрос: Пропустит ли компилятор такой код и почему ?

42.

Строки как массивы
Ответ:

43.

Строки как массивы
Ответ: компилятор не пропустит такой код, потому что str – это
указатель на константу типа char.
Поэтому значение переменной, адрес которой хранится в указателе
str (т.е. саму строку) изменить нельзя.
Значение же самого указателя изменить можно, потому что это
переменная.

44.

Передача строк в функцию
Передача строк в функцию по указателю осуществляется
аналогично передаче в функцию массивов по указателю.

45.

Передача строк в функцию
Передача строк в функцию по указателю осуществляется
аналогично передаче в функцию массивов по указателю.

46.

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

47.

Массивы строк
Вопрос: пропустит ли компилятор такой код и что мы увидим на
экране в этом случае ?

48.

Массивы строк
Ответ:

49.

Массивы строк
Вопрос: пропустит ли компилятор такой код и что мы увидим на
экране в этом случае ?

50.

Массивы строк
Ответ:

51.

Массивы строк
Вопрос: пропустит ли компилятор такой код и что мы увидим на
экране в этом случае ?

52.

Массивы строк
Ответ:

53.

Массивы строк
Вопрос: пропустит ли компилятор такой код и что мы увидим на
экране в этом случае ?

54.

Массивы строк
Ответ:
Каждый элемент массива str – это указатель на константу!

55.

Динамический массив char-строк.

56.

Динамический массив char-строк

57.

Динамический массив строк типа string

58.

Динамический массив строк типа string

59.

Санкт-Петербургский государственный
архитектурно-строительный университет
кафедра информационных технологий
Автор:
Букунов Сергей Витальевич
[email protected]
English     Русский Правила