Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Programmirovanie_-_1_kurs / Методические указания к лабораторным работам 3-4

.pdf
Скачиваний:
61
Добавлен:
09.06.2015
Размер:
700.69 Кб
Скачать

int A[3][5] = { {1,2,3,4,5}, {6,7,8,9,10}, {11,12,13,14,15} };

cout << A[2][1]; // 12 cout << A[1][2]; // 8 cout << A[0][4]; // 5

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

int A[][5] = { {1,2,3,4,5}, {6,7,8,9,10}, {11,12,13,14,15} };

1.4.1. Представление массива в памяти

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

Многомерные массивы представлены в памяти линейно. Например, элементы массива A:

int A[3][5] = { {1,2,3,4,5}, {6,7,8,9,10}, {11,12,13,14,15} };

будут размещены в памяти следующим образом (рис. 4):

Рисунок 4. Представление многомерного массива в памяти

1.5. Упорядочивание массива

Одна из типовых задач, возникающая при работе с одномерными массивами, – это упорядочивание элементов массива по их значениям.

Существует большое количество стандартных алгоритмов по упорядочиванию массива. Ниже мы

10

рассмотрим два основных алгоритма: сортировка методом выбора и сортировка методом «пузырька».

1.5.1. Сортировка выбором

Алгоритм состоит в том, что выбирается наименьший элемент массива и меняется местами с первым элементом. Затем рассматриваются элементы, начиная со второго, и наименьший из них меняется местами со вторым элементом, и так далее n-1 раз (n – размер массива). При последнем проходе цикла при необходимости меняются местами предпоследний и последний элементы массива.

Итак, предположим, у нас имеется одномерный массив A, содержащий n элементов.

Выполним его упорядочивание методом выбора.

// Проходим по всем элементам for (int i=0; i<n-1; i++)

{

//Запоминаем i-й элемент как минимальный int min_ind = i; // Номер миним. элемента int min_val = A[i]; // Минимальное значение

//Проходим по элементам, начиная с i+1-го,

//и находим минимальный элемент

for (int j=i+1; j<n; j++)

//Если элемент с номером j меньше min_val,

//то запоминаем этот элемент как минимальный if (A[j]<min_val)

{

min_ind = j; min_val = A[j];

}

//Меняем местами элемент с номером i

//и минимальный элемент

A[min_ind] = A[i]; A[i] = min_val;

}

11

1.5.2. Сортировка «пузырьком»

Алгоритм состоит в повторяющихся проходах по сортируемому массиву. За каждый проход элементы последовательно сравниваются попарно и, если порядок в паре неверный, выполняется обмен элементов. Проходы по массиву повторяются до тех пор, пока на очередном проходе не окажется, что обмены больше не нужны, что означает — массив отсортирован. В результате работы алгоритма, элемент, стоящий не на своём месте, «всплывает» до нужной позиции как пузырёк в воде, отсюда и название алгоритма.

bool t; // Признак отсортированного массива do

{

t = true; // Предположим,

//что массив уже отсортирован

//Проходим по элементам массива

for (int i=0; i<n-1; i++)

//Если элемент с меньшим индексом

//имеет большее значение

if (A[i] > A[i+1])

{

// Меняем соседние элементы местами int temp = A[i+1];

A[i+1]

=

A[i];

A[i]

=

temp;

//Отмечаем, что массив

//еще не отсортирован t = false;

}

} while(!t);

2. ПОЛЬЗОВАТЕЛЬСКИЕ ТИПЫ ДАННЫХ

2.1. Перечисления

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

12

специальной конструкции перечислений. Перечисление обозначается при помощи ключевого слова enum.

Рассмотрим следующую конструкцию:

enum {RED, GREEN, BLUE};

Здесь определены три целых константы, которые называются элементами перечисления. Значения элементов перечисления по умолчанию начинаются с нуля и идут в возрастающем порядке. Приведенное выше перечисление эквивалентно следующим определениям:

const int RED = 0; const int GREEN = 1; const int BLUE = 2;

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

пользовательским типом данных.

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

enum color {RED, GREEN, BLUE};

Теперь, в программе можно определять переменные, относящиеся к типу данных color. Такие переменные смогут принимать всего лишь три значения: RED, GREEN

или BLUE:

//Объявляем переменную типа color: color A;

//Присваиваем переменной A значение RED: A = RED;

//Присваиваем переменной A значение GREEN: A = GREEN;

//Присваиваем переменной A значение 2 (BLUE): A = 2; // !!! ОШИБКА, несоответствие типов

A = (color)2; // нужно делать так

Для элементов перечисления можно явно указать их значения. Задаваемые значения должны быть различными, неотрицательными и идти в возрастающем порядке:

enum color {RED = 100, GREEN = 200, BLUE = 350};

13

2.2. Структуры

Автоматизируемые объекты описываются в программе при помощи определенного набора характеристик (свойств). За каждую характеристику в программе отвечает соответствующая переменная. Например, для описания прямоугольника можно использовать две характеристики: ширина и длина:

double width; // Ширина прямоугольника double height; // Длина прямоугольника

В случае если нам потребуется описать три прямоугольника, то таких переменных будет уже шесть, что, согласитесь, не очень удобно:

double width1; // Ширина прямоугольника 1 double height1; // Длина прямоугольника 1 double width2; // Ширина прямоугольника 2 double height2; // Длина прямоугольника 2 double width3; // Ширина прямоугольника 3 double height3; // Длина прямоугольника 3

Вбольшом количестве переменных легко запутаться. Гораздо удобнее было бы использовать один идентификатор для работы с отдельным прямоугольником.

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

Структура может быть представлена как некоторый набор разнотипных или однотипных данных, совокупность которых рассматривается как совершенно новый,

пользовательский тип данных.

2.2.1. Объявление структуры

Структура объявляется с помощью ключевого слова struct, за которым следует необязательный идентификатор, обозначающий имя нового типа данных, и указываемый в фигурных скобках перечень переменных (свойств, полей

14

или членов структуры). Блок описания структуры заканчивается символом точка с запятой.

struct имя_структуры

{

тип1 поле1; тип2 поле2;

...

типN полеN;

};

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

struct rectangle

{

double width; double height;

};

Еще один пример демонстрирует объявление структуры circle, описывающей окружность. Данная структура содержит поля, определяющие координаты центра окружности (x и y), а также ее радиус (radius):

struct circle

{

int x; int y;

int radius;

};

2.2.2. Объекты структурного типа

После того как структура определена, мы можем с ее помощью объявлять переменные – объекты структуры.

Итак, для того чтобы описывать объекты категории «прямоугольник» мы определили новый тип данных:

struct rectangle

{

double width; double height;

};

15

Объявим три переменные, относящиеся к новому типу:

rectangle rect1; // Прямоугольник 1 rectangle rect2; // Прямоугольник 2 rectangle rect3; // Прямоугольник 3

Каждая из переменных (rect1, rect2, rect3) содержит внутри себя поля, заданные для структуры rectangle.

Для обращения к полям структурированных объектов используется специальная операция, обозначаемая при помощи символа точка:

//Установить длину прямоугольника 1 rect1.height = 10;

//Установить ширину прямоугольника 1 rect1.width = 15;

//Установить длину прямоугольника 2 rect2.height = rect1.width;

//Установить ширину прямоугольника 2 rect2.width = rect2.height*2;

Применительно к структурированным переменным допускается непосредственное использование оператора присваивания:

rect3 = rect1; // Так делать МОЖНО

Большинство стандартных операций не определены для структур. Например, мы не можем сравнивать две структуры при помощи операций ==, !=, > или <.

if (rect3 == rect1) ... // !!! Так делать НЕЛЬЗЯ

Объявление объектов структуры может быть выполнено в блоке описания самой структуры:

struct rectangle

{

double width; double height;

} rect1, rect2, rect3;

// rect1, rect2, rect3 – объекты типа rectangle

При объявлении объектов структуры можно выполнить инициализацию значений их полей. Начальные значения

16

полей указываются в фигурных скобках в порядке, в котором поля объявлены внутри структуры:

rectangle rect1 = {10,15};

//Инициализация выполнена следующим образом:

//rect1.width = 10;

//rect1.height = 15;

2.2.3. Примеры сложных структур

Поля структур могут являться массивами или, в свою очередь, объектами других структур.

Предположим, мы хотим хранить информацию о пятиугольнике на плоскости. Пятиугольник состоит из пяти точек, каждая точка имеет две координаты: x и y.

Определим соответствующую структуру:

struct pentagon

{

int x[5]; int y[5];

};

Теперь, объявим объект пятиугольник и установим значения для его полей:

pentagon P;

P.x[0] = 0; // Координаты точки №1

P.y[0] = 0;

P.x[1] = 10; // Координаты точки №2

P.y[1] = 0;

P.x[2] = 15; // Координаты точки №3

P.y[2] = 5;

P.x[3] = 10; // Координаты точки №4

P.y[3] = 10;

P.x[4] = 0; // Координаты точки №5

P.y[4] = 10;

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

17

struct point

{

int x; int y;

};

Окружность задается координатами центра и радиусом. Для хранения информации о координатах центра окружности мы можем использовать определенную ранее структуру point. Таким образом, структура circle – окружность – будет выглядеть следующим образом:

struct circle

{

point center; int radius;

};

Объявим окружность с радиусом 35 единиц и координатами центра (100, 50):

circle A; A.center.x = 100; A.center.y = 50; A.radius = 35;

2.3. Объявление новых типов данных (typedef)

Вязыке С++ существует возможность создавать новые пользовательские типы данных на основе существующих. Для определения нового пользовательского типа используется ключевое слово typedef.

После ключевого слова typedef указывается какой-либо из имеющихся типов данных, а за ним – идентификатор, обозначающий имя для нового типа.

Вследующем примере мы определим новый тип данных BYTE, являющийся синонимом стандартного типа unsigned char:

typedef unsigned char BYTE; BYTE a;

18

В следующем примере мы определим новый тип данных matrix на основе двумерного массива. Тип matrix будет использоваться для представления целочисленных матриц размером 10 х 10:

typedef int matrix[10][10]; matrix a;

for (int i=0; i<10; i++) for (int j=0; j<10; j++)

a[i][j] = i + j;

2.4. Оператор sizeof

Под каждую объявленную переменную в памяти выделяется определенное пространство. Например, для переменной типа short int отводится 2 байта, а для переменной типа double – 8 байт.

Для массивов в памяти отводится место, равное произведению количества элементов на размер одного элемента. Например, для массива, состоящего из 10 элементов типа short int, в памяти будет выделено 20 байт.

Сложнее обстоят дела со структурами. В общем случае, размер объекта структурного типа может не быть равен сумме размеров его полей. Например, объекты следующей структуры test будут занимать в памяти 16 байт (несмотря на то, что сумма размеров полей равна 13 байтам):

struct test

{

char h; // поле занимает 1 байт в памяти int b; // поле занимает 4 байта в памяти double f; // поле занимает 8 байт в памяти

} Y; // переменная Y займет в памяти 16 байт

Это происходит по той причине, что на многих машинах требуется размещать объекты определенных типов, только выравнивая их по некоторой зависящей от системы адресации границе (или просто потому, что работа при таком выравнивании будет более эффективной).

19