Приветствую Вас Гость | RSS

ALLDev

Суббота, 21.12.2024, 16:08
Главная » Статьи » Программирование » C/C++/C#

Учебник C++. Производные типы данных. Часть 1

Массивы

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

int days[12]; 
days[0] = 31; // январь
days[1] = 28; // февраль
days[2] = 31; // март
days[3] = 30; // апрель
days[4] = 31; // май
days[5] = 30; // июнь
days[6] = 31; // июль
days[7] = 31; // август
days[8] = 30; // сентябрь
days[9] = 31; // октябрь
days[10] = 30; // ноябрь
days[11] = 31; // декабрь

В первой строчке мы объявили массив из 12 элементов типа int и дали ему имя days. Остальные строки примера – присваивания значений элементаммассива. Для того, чтобы обратиться к определенному элементу массива, используют операцию индексации []. Как видно из примера, первый элементмассива имеет индекс 0, соответственно, последний – 11.

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

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

for (int i = 0; i < 12; i++) {
 cout << days[i];
}

Следует отметить, что при выполнении программы границы массива не контролируются. Если мы ошиблись и вместо 12 в приведенном выше цикле написали 13, то компилятор не выдаст ошибку. При выполнении программа попытается напечатать 13 -е число. Что при этом случится, вообще говоря, не определено. Быть может, произойдет сбой программы. Более вероятно, что будет напечатано какое-то случайное 13 -е число. Выход индексов за границы массива – довольно распространенная ошибка, которую иногда очень трудно обнаружить. В дальнейшем при изучении классов мы рассмотрим, как можно переопределить операцию [] и добавить контроль за индексами.

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

Рассмотрим еще один пример. Предположим, что имеется массив из 100 целых чисел, и его необходимо отсортировать, т.е. расположить в порядке возрастания. Сортировка методом "пузырька" – наиболее простая и распространенная – будет выглядеть следующим образом:

int array[100];
. . .
for (int i = 0; i < 99; i++ ) {
 for (int j = i + 1; j < 100; j++) {
 if (array[j] < array[i] ) {
 int tmp = array[j];
 array[j] = array[i];
 array[i] = tmp;
 }
 }
}

В приведенных примерах у массивов имеется только один индекс. Такие одномерные массивы часто называются векторами. Имеется возможность определить массивы с несколькими индексами или размерностями. Например, объявление

int m[10][5];

представляет матрицу целых чисел размером 10 на 5. По-другому интерпретировать приведенное выше объявление можно как массив из 10 элементов, каждый из которых – вектор целых чисел длиной 5. Общее количество целых чисел в массиве   m равно 50.

Обращение к элементам многомерных массивов аналогично обращению к элементам векторов: m[1][2] обращается к третьему элементу второй строки матрицы m.

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

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

int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

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

double temp[2][3] = {
 { 3.2, 3.3, 3.4 },
 { 4.1, 3.9, 3.9 } };

Интересной особенностью инициализации многомерных массивов является возможность не задавать размеры всех измерений массива, кроме самого последнего. Приведенный выше пример можно переписать так:

double temp[][3] = {
 { 3.2, 3.3, 3.4 },
 { 4.1, 3.9, 3.9 } };
// Вычислить размер пропущенной размерности
const int size_first = sizeof (temp) / sizeof 
 (double[3]);

Структуры

Структуры – это не что иное, как классы, у которых разрешен доступ ко всем их элементам (доступ к определенным атрибутам класса может быть ограничен, о чем мы узнаем в лекции 11). Пример структуры:

struct Record {
 int number;
 char name[20];
};

Так же, как и для классов, операция " ." обозначает обращение к элементу структуры.

В отличие от классов, можно определить переменную- структуру без определения отдельного типа:

struct {
 double x;
 double y;
} coord;

Обратиться к атрибутам переменной coord можно coord.x и coord.y.

Битовые поля

В структуре можно определить размеры атрибута с точностью до бита. Традиционно структуры используются в системном программировании для описания регистров аппаратуры. В них каждый бит имеет свое значение. Не менее важной является возможность экономии памяти – ведь минимальный тип атрибута структуры это байт ( char ), который занимает 8 битов. До сих пор, несмотря на мегабайты и даже гигабайты оперативной памяти, используемые в современных компьютерах, существует немало задач, где каждый бит на счету.

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

struct TimeAndDate
{
unsigned hours :5; // часы от 0 до 24 
unsigned mins :6; // минуты 
unsigned secs :6; // секунды от 0 до 60
unsigned weekDay :3; // день недели
unsigned monthDay :6; // день месяца от 1 до 31
unsigned month :5; // месяц от 1 до 12
unsigned year :8; // год от 0 до 100 
};

Одна структура   TimeAndDate требует всего 39 битов, т.е. 5 байтов (один байт — 8 битов). Если бы мы использовали для каждого атрибута этой структуры тип char, нам бы потребовалось 7 байтов.

Объединения

Особым видом структур данных является объединение. Определение объединения напоминает определение структуры, только вместо ключевого слова struct используется union:

union number {
 short sx;
 long lx;
 double dx;
};

В отличие от структуры, все атрибуты объединения располагаются по одному адресу. Под объединение выделяется столько памяти, сколько нужно для хранения наибольшего атрибутаобъединенияОбъединения применяются в тех случаях, когда в один момент времени используется только один атрибут объединения и, прежде всего, для экономии памяти. Предположим, нам нужно определить структуру, которая хранит "универсальное" число, т.е. число одного из предопределенных типов, и признак типа. Это можно сделать следующим образом:

struct Value {
 enum NumberType { ShortType, LongType,
 DoubleType };
 NumberType type; 
 short sx; // если type равен ShortType
 long lx; // если type равен LongType
 double dx; // если type равен DoubleType
};

Атрибут type содержит тип хранимого числа, а соответствующий атрибут структуры – значение числа.

Value shortVal;
shortVal.type = Value::ShortType;
shortVal.sx = 15;

Хотя память выделяется под все три атрибута sxlx и dx, реально используется только один из них. Сэкономить память можно, используя объединение:

struct Value {
 enum NumberType { ShortType, LongType, 
 DoubleType };
 NumberType type;
 union number { 
 short sx; // если type равен ShortType
 long lx; // если type равен LongType
 double dx; // если type равен DoubleType
 } val;
};

Теперь память выделена только для максимального из этих трех атрибутов (в данном случае dx ). Однако и обращаться с объединением надо осторожно. Поскольку все три атрибута делят одну и ту же область памяти, изменение одного из них означает изменение всех остальных. На рисунке поясняется выделение памяти под объединение. В обоих случаях мы предполагаем, чтоструктура расположена по адресу 1000. Объединение располагает все три своих атрибута по одному и тому же адресу.

Использование памяти в объединениях.

Рис. 8.1.  Использование памяти в объединениях.

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

Категория: C/C++/C# | Добавил: artkil (23.09.2012)
Просмотров: 1979 | Комментарии: 2 | Теги: Array, массив, c++ | Рейтинг: 0.0/0
Всего комментариев: 1
1 pegoret  
0
Срочно требуются. Обработка зказов на дому.

Без вложений, на системе автоматического приёма и обработки заказов.

Более подробная информация у нас на сайте. > obrabotka.zarplatt(точка)ru <

Имя *:
Email *:
Код *: