20
Модуль 2 : Составные типы данных и работа с динамической памятью. Темы лекции : Массивы и указатели. Практическое задание : Алгоритмы сортировки массивов. Тренер: Игорь Шкулипа, к.т.н. C++ Базовый. Занятие 5

C++ Базовый. Занятие 05

Embed Size (px)

Citation preview

Page 1: C++ Базовый. Занятие 05

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

Темы лекции: Массивы и указатели.

Практическое задание: Алгоритмы сортировки массивов.

Тренер: Игорь Шкулипа, к.т.н.

C++ Базовый. Занятие 5

Page 2: C++ Базовый. Занятие 05

http://www.slideshare.net/IgorShkulipa 2

Массив

Массив - это совокупность данных одного типа, к которым обращаются спомощью общего имени.

Доступ к отдельному элементу массива может осуществляться с помощьюиндекса.

В С++ все массивы состоят из соприкасающихся участков памяти.Наименьший адрес соответствует первому элементу. Наибольшийадрес соответствует последнему элементу.

Массивы могут иметь одну или несколько размерностей.

Каждый элемент массива может использоваться, как отдельнаяпеременная

Page 3: C++ Базовый. Занятие 05

http://www.slideshare.net/IgorShkulipa 3

Одномерный массив

Стандартный вид объявления одномерного массива следующий:

<тип> <имя_переменной> [<размер>];

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

Здесь <тип> объявляет базовый тип массива и является типом каждого

элемента массива.

Параметр <размер> определяет, сколько элементов содержит массив.

В одномерном массиве полный размер массива в байтах вычисляетсяследующим образом:

<общее число байт> = sizeof (<тип>) *<количество элементов>

У всех массивов первый элемент имеет индекс 0. Поэтому

char charArray[10];

объявляет массив символов из 10 элементов, причем эти элементыадресуются индексом от 0 до 9.

Page 4: C++ Базовый. Занятие 05

http://www.slideshare.net/IgorShkulipa 4

Объявление и определение массивов

int array1[];

Объявлен массив типа int, имя массива - array1

int array2[10];

Определен массив типа int, размером 10 элементов

int array3[<константное выражение>];

Определен массив типа int, размером <константное выражение>

элементов

int array4[3]={1,2,3};

В этом определении массива важно, чтобы количество элементов винициализаторе массива не превышало значение константноговыражения в описателе массива.

int array5[]={1,2,3};

Количество элементов массива становится известным компилятору прианализе инициализатора.

Page 5: C++ Базовый. Занятие 05

http://www.slideshare.net/IgorShkulipa 5

Частичная инициализация массивов

int array6[3]={1,2};

Возможна частичная инициализация массива. При этом значенияполучают первые элементы массива. Значение последнего элементамассива в общем случае не определено (обычно равно 0).

int array7[3]={1,2,};

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

Page 6: C++ Базовый. Занятие 05

http://www.slideshare.net/IgorShkulipa 6

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

int array[] = { 0, 1, 2, 4, 8, 16, 32, 64, 128, 256 };

array[0]=0; // доступ к нулевому элементу

array[1]=1; // доступ к первому элементу

array[2]=2; // доступ ко второму элементу

...

array[9]=256; // доступ к девятому элементу

Следующее выражение меняет местами 6 и 8 элемент массива:

array[6]=array[6]+array[8];

array[8]=array[6]-array[8];

array[6]=array[6]-array[8];

Page 7: C++ Базовый. Занятие 05

http://www.slideshare.net/IgorShkulipa 7

Многомерные массивы

В С++ есть возможность использовать многомерные массивы, приобъявлении которых необходимо указать размер каждого измерения вотдельных квадратных скобках.

int array1[4][3];

Многомерные массивы тоже могут быть инициализированы:

int array2[4][3] = {{0,1,2},{3,4,5},{6,7,8},{9,10,11}};

Внутренние фигурные скобки, разбивающие список значений на строки,необязательны и используются, как правило, для удобства чтениякода.

int array3[4][3] = { 0,1,2,3,4,5,6,7,8,9,10,11 };

Инициализация массива array3 полностью эквивалентна array2

Page 8: C++ Базовый. Занятие 05

http://www.slideshare.net/IgorShkulipa 8

Многомерные массивы

int array4[4][3] = {{0},{3},{6},{9}};

Это определение инициализирует только первые элементы каждой строки.Оставшиеся элементы будут равны нулю.

int array5[4][3] = {0,3,6,9};

Если же опустить внутренние фигурные скобки, то три элемента первой строки ипервый элемент второй получат указанное значение, а остальные будутинициализированы 0.

При обращении к элементам многомерного массива необходимо использоватьиндексы для каждого измерения (они заключаются в квадратные скобки). Таквыглядит инициализация двумерного массива с помощью вложенных циклов:

int main()

{

const int iRows = 4;

const int iCols = 3;

int array[iRows][iCols];

for ( int i = 0; i < iRows; i++ )

for ( int j = 0; j < iCols; j++ )

array[i][j] = i + j;

}

Page 9: C++ Базовый. Занятие 05

http://www.slideshare.net/IgorShkulipa 9

Динамическая память

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

Динамическая память — это свободная область памяти, неиспользуемая программой, операционной системой или другимипрограммами. Размер динамически распределяемой области памятизаранее неизвестен, но, как правило, ограничен объемом оперативнойпамяти вычислительной системы.

Page 10: C++ Базовый. Занятие 05

http://www.slideshare.net/IgorShkulipa 10

Указатели

Указатели - это практически то же самое, что и переменные. Ониотличаются тем, что вместо того, чтобы содержать данные, онисодержат адрес памяти, где данная информация может бытьнайдена.

Для объявления указателя существует следующая конструкция:

<тип> * <имя переменной>

Например:

int* pointer1;

int* pointer2;

Указатели имеют тип, который определяет размер ячейки памяти и тип хранимого в ней значения.

Page 11: C++ Базовый. Занятие 05

http://www.slideshare.net/IgorShkulipa 11

Разыменование и взятие адреса

Основной операцией при работе с указателями является получениедоступа к значению, адрес которого хранится в указателе.

Например:

int *intPointer, intVariable;

*intPointer = 5;

intVariable = *intPointer;

Выражение *intPointer имеет такой же смысл, как имя целой

переменной. Операция * называется разыменованием.

Действие, обратное к разыменованию, позволяет получить адреспеременной по ее имени. Эта операция называется взятие адреса.

Например:

intPointer = &intVariable;

Page 12: C++ Базовый. Занятие 05

http://www.slideshare.net/IgorShkulipa 12

Выделение памяти под указатель (malloc)

Основу системы динамического распределения в С составляют функцииmalloc() и free(). Эти функции работают совместно. Функция malloc()

выделяет память, а free() — освобождает ее. Это значит, что при каждомзапросе функция malloc() выделяет требуемый участок свободнойпамяти, a free() освобождает его, то есть возвращает системе. В

программу, использующую эти функции, должен быть включензаголовочный файл <stdlib.h>.

void *malloc(<количество_байтов>);

Например:

char *p;

// выделение 1000 байт памяти

p = (char*)malloc(1000);

// выделение 50*sizeof(int), т.е. 200 байт памяти

p = (char*)malloc(50*sizeof(int));

Page 13: C++ Базовый. Занятие 05

http://www.slideshare.net/IgorShkulipa 13

Освобождение памяти указателя (free)

Функция free() возвращает системе участок памяти, выделенный ранеес помощью функции malloc(). Иными словами, она освобождает

участок памяти, который может быть вновь использован функциейmalloc().

Функция free() имеет следующий прототип:

void free(void *p)

Например:

char *p;

// выделение 1000 байт памяти

p = malloc(1000);

// освобождение памяти

free (p);

// выделение 50*sizeof(int), т.е. 200 байт памяти

p = malloc(50*sizeof(int));

// освобождение памяти

free (p);

Page 14: C++ Базовый. Занятие 05

http://www.slideshare.net/IgorShkulipa 14

Выделение памяти под указатель (new)

Выделение памяти объекту может производиться с помощью оператора new,

возвращающего указатель на вновь созданный объект того типа, которыйбыл ему задан.

int *p = new int;

Размещает объект типа int в памяти и инициализирует указатель p адресом

этого объекта. Сам объект в таком случае не инициализируется.

Чтобы инициализировать объект в памяти, используется следующаяконструкция.

int *p = new int(10);

Можно динамически выделить память под массив:

int *p = new int[10];

Такая инструкция размещает в памяти массив из десяти элементов типа int.

Page 15: C++ Базовый. Занятие 05

http://www.slideshare.net/IgorShkulipa 15

Освобождение памяти указателя (delete)

После использования объекта, созданного с помощью оператора new, мыдолжны явно освободить память, применив оператор delete к

указателю на этот объект.

(!) Попытка применить оператор delete к указателю, не содержащему

адрес объекта, полученного описанным способом, вызовет ошибкувремени выполнения.

delete p;

Освобождает память, на которую указывает указатель p.

delete[] p;

Освобождает память, отведенную под массив p.

Page 16: C++ Базовый. Занятие 05

http://www.slideshare.net/IgorShkulipa 16

Связь массивов и указателей

Если мы имеем определение массива:

int array[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

То использование идентификатора массива в программе эквивалентноуказанию адреса его первого элемента:

array == &array[0];

*array == array[0];

Соответственно:

&array[1] == array+1;

array[1]==*(array+1)

* - операция разыменования указателя, то есть значение ячейкипамяти, на которую он указывает

Page 17: C++ Базовый. Занятие 05

http://www.slideshare.net/IgorShkulipa 17

Операции с указателями

Над указателями можно выполнять унарные операции: инкремент идекремент. При выполнении операций ++ и -- значение указателяувеличивается или уменьшается на длину типа, на который ссылаетсяиспользуемый указатель.

int *pointer;

int array[10];

pointer=&array[5];

pointer++; //адрес элемента a[6]

pointer--; //адрес элемента a[5]

В бинарных операциях сложения и вычитания могут участвоватьуказатель и величина типа int. При этом результатом операции будет

указатель на исходный тип, а его значение будет на указанное числоэлементов больше или меньше исходного.

int *pointer1, *pointer2;

int array[10];

pointer1=array+4; //адрес элемента a[4]

pointer2=pointer1-2; //адрес элемента a[2]

Page 18: C++ Базовый. Занятие 05

http://www.slideshare.net/IgorShkulipa 18

Операции с указателями

В операции вычитания могут участвовать два указателя на один и тот жетип. Результат такой операции имеет тип int и равен числу элементов

исходного типа между уменьшаемым и вычитаемым, причем еслипервый адрес младше, то результат имеет отрицательное значение.

int *pointer1, *pointer2, array[10], i;

pointer1=array+4;

pointer2=array+9;

i=pointer1-pointer2; // i==5

i=pointer2-pointer1; // i==-5

Значения двух указателей на одинаковые типы можно сравнивать воперациях == != < <= > >= при этом значения указателейрассматриваются просто как целые числа.

int *pointer1, *pointer2, array[10], i;

pointer1=array+4;

pointer2=array+9;

if (pointer1 > pointer2) array[5]=10;

Page 19: C++ Базовый. Занятие 05

http://www.slideshare.net/IgorShkulipa 19

Передача массивов в функции

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

void arrayFunction(int array[10]);

void arrayFunction(int array[]);

void arrayFunction(int *array);

Для многомерных массивов:

void arrayFunction(int array[10][10]);

void arrayFunction(int array[][10]);

void arrayFunction(int **array);

Page 20: C++ Базовый. Занятие 05

http://www.slideshare.net/IgorShkulipa 20

Лабораторная работа №5

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

⚫ Быстрой сортировки (1, 7, 13)

⚫ Сортировки Шелла (2, 8, 14)

⚫ Сортировки простыми вставками (3, 9, 15)

⚫ Пирамидальной сортировки (4, 10)

⚫ Сортировки “шейкерным” методом (5, 11)

⚫ Поразрядной сортировки (6, 12)

Реализовать параметризацию функции сортировки по возрастанию и поубыванию элементов.

Оформить методы сортировки в виде отдельного модуля, размещенного вотдельном подключаемом файле.