С++ предоставляет встроенную поддержку для основных типов данных – целых и вещественных чисел, логических значений и символов. К числовым типам данных могут применяться встроенные арифметические и логические операции: объекты числового типа можно складывать, вычитать, умножать, делить и т.д.
В дополнение к встроенным типам стандартная библиотека С++ предоставляет поддержку для расширенного набора типов, таких, как строка и комплексное число.
Промежуточное положение между встроенными типами данных и типами данных из стандартной библиотеки занимают составные типы – массивы и указатели.
1 2 3 4 5 6 7 8 9 10 11 |
// объявление целого объекта ival // ival инициализируется значением 1024 int ival = 1024; // объявление вещественного объекта двойной точности dval // dval инициализируется значением 3.14159 double dval = 3.14159; // объявление вещественного объекта одинарной точности fval // fval инициализируется значением 3.14159 float fval = 3.14159; |
1 2 3 4 5 6 7 8 9 10 |
int ival2 = ival1 + 4096; // сложение int ival3 = ival2 - ival; // вычитание dval = fval * ival; // умножение ival = ival3 / 2; // деление bool result = ival2 == ival3; // сравнение на равенство result = ival2 + ival != ival3; // сравнение на неравенство result = fval + ival2 < dval; // сравнение на меньше result = ival > ival2; // сравнение на больше |
Массив – это упорядоченный набор элементов одного типа. Например, последовательность:
1 |
0 1 1 2 3 5 8 13 21 |
представляет собой первые 9 элементов последовательности Фибоначчи. (Выбрав начальные два числа, вычисляем каждый из следующих элементов как сумму двух предыдущих.)
Для того чтобы объявить массив и проинициализировать его данными элементами, мы должны написать следующую инструкцию С++:
1 |
int fibon[9] = { 0, 1, 1, 2, 3, 5, 8, 13, 21 }; |
Здесь fibon – это имя массива. Элементы массива имеют тип int, размер (длина) массива равна 9. Значение первого элемента – 0, последнего – 21. Для работы с массивом мы индексируем (нумеруем) его элементы, а доступ к ним осуществляется с помощью операции взятия индекса. Казалось бы, для обращения к первому элементу массива естественно написать:
1 |
int first_elem = fibon[1]; |
Однако это не совсем правильно: в С++ (как и в С) индексация массивов начинается с 0, поэтому элемент с индексом 1 на самом деле является вторым элементом массива, а индекс первого равен 0.Таким образом, чтобы обратиться к последнему элементу массива, мы должны вычесть единицу из размера массива:
1 2 3 4 5 |
fibon[0]; // первый элемент fibon[1]; // второй элемент ... fibon[8]; // последний элемент fibon[9]; // ... ошибка |
Девять элементов массива fibon имеют индексы от 0 до 8. Употребление вместо этого индексов 1-9 является одной из самых распространенных ошибок начинающих программистов на С++. Для перебора элементов массива обычно употребляют инструкцию цикла. Вот пример программы, которая инициализирует массив из десяти элементов числами от 0 до 9 и затем печатает их в обратном порядке:
1 2 3 4 5 6 7 8 9 10 11 |
int main() { int ia[10]; int index; for (index=0; index<10; ++index) // ia[0] = 0, ia[1] = 1 и т.д. ia[index] = index; for (index=9; index>=0; --index) cout « ia[index] « " "; cout « endl; } |
Оба цикла выполняются по 10 раз. Все управление циклом for осуществляется инструкциями в круглых скобках за ключевым словом for. Первая присваивает начальное значение переменной index. Это производится один раз перед началом цикла:
1 |
index = 0; |
Вторая инструкция:
1 |
index < 10; |
представляет собой условие окончания цикла. Оно проверяется в самом начале каждой итерации цикла <strong>. Если результатом этой инструкции является true, то выполнение цикла продолжается; если же результатом является false, цикл заканчивается </strong>. В нашем примере цикл продолжается до тех пор, пока значение переменной index меньше 10. На каждой итерации цикла выполняется некоторая инструкция или группа инструкций, составляющих тело цикла. В нашем случае это инструкция
1 |
ia[index] = index; |
Третья управляющая инструкция цикла
1 |
++index |
выполняется в конце каждой итерации, по завершении тела цикла. В нашем примере это увеличение переменной index на единицу. Мы могли бы записать то же действие как
1 |
index = index + 1 |
но С++ дает возможность использовать более короткую (и более наглядную) форму записи. Этой инструкцией завершается итерация цикла. Описанные действия повторяются до тех пор, пока условие цикла не станет ложным.
Вторая инструкция for в нашем примере печатает элементы массива. Она отличается от первой только тем, что в ней переменная index уменьшается от 9 до 0.
Несмотря на то, что в С++ встроена поддержка для типа данных “массив”, она весьма ограничена. Фактически мы имеем лишь возможность доступа к отдельным элементам массива. С++ не поддерживает абстракцию массива, не существует операций над массивами в целом, таких, например, как присвоение одного массива другому или сравнение двух массивов на равенство, и даже такой простой, на первый взгляд, операции, как получение размера массива. Мы не можем скопировать один массив в другой, используя простой оператор присваивания:
1 2 3 4 5 6 |
int array0[10]; array1[10]; ... array0 = array1; // ошибка Вместо этого мы должны программировать такую операцию с помощью цикла: for (int index=0; index<10; ++index) array0[index] = array1[index]; |
Массив “не знает” собственный размер. Поэтому мы должны сами следить за тем, чтобы случайно не обратиться к несуществующему элементу массива. Это становится особенно утомительным в таких ситуациях, как передача массива функции в качестве параметра. Можно сказать, что этот встроенный тип достался языку С++ в наследство от С и процедурно-ориентированной парадигмы программирования. В оставшейся части главы мы исследуем разные возможности “улучшить” массив.