if (условие)
оператор1
else
оператор2
Если условие истинно, выполняется оператор1, если ложно, то выполняется оператор2.
if (x > y)
a = x;
else
a = y;
В данном примере переменной a присваивается значение максимума из двух величин x и y.
Конструкция else необязательна. Можно записать:
if (x < 0)
x = -x;
abs = x;
В данном примере оператор x = -x; выполняется только в том случае, если значение переменной x было отрицательным. Присваивание переменной abs выполняется в любом случае. Таким образом, приведенный фрагмент программы изменит значение переменной x на его абсолютное значение и присвоит переменной abs новое значение x.
Если в случае истинности условия необходимо выполнить несколько операторов, их можно заключить в фигурные скобки:
if (x < 0) {
x = -x;
cout << "Изменить значение x на
противоположное по знаку";
}
abs = x;
Теперь если x отрицательно, то не только его значение изменится на противоположное, но и будет выведено соответствующее сообщение. Фактически, заключая несколько операторов в фигурные скобки, мы сделали из них один сложный оператор или блок. Прием заключения нескольких операторов в блок работает везде, где нужно поместить несколько операторов вместо одного.
Условный оператор можно расширить для проверки нескольких условий:
if (x < 0)
cout << "Отрицательная величина";
else if (x > 0)
cout << "Положительная величина";
else
cout << "Ноль";
Конструкций else if может быть несколько.
Хотя любые комбинации условий можно выразить с помощью оператора if, довольно часто запись становится неудобной и запутанной. Оператор выбора switch используется, когда для каждого из нескольких возможных значений выражения нужно выполнить определенные действия. Например, предположим, что в переменной code хранится целое число от 0 до 2, и нам нужно выполнить различные действия в зависимости от ее значения:
switch (code) {
case 0:
cout << "код ноль";
x = x + 1;
break;
case 1 :
cout << "код один";
y = y + 1;
break;
case 2:
cout << "код два";
z = z + 1;
break;
default:
cout << "Необрабатываемое значение";
}
В зависимости от значения code управление передается на одну из меток case. Выполнение оператора заканчивается по достижении либо оператора break, либо конца оператора switch. Таким образом, если code равно 1, выводится "код один", а затем переменная y увеличивается на единицу. Если бы после этого не стоял оператор break, то управление "провалилось" бы дальше, была бы выведена фраза "код два", и переменная z тоже увеличилась бы на единицу.
Если значение переключателя не совпадает ни с одним из значений меток case, то выполняются операторы, записанные после метки default. Метка default может быть опущена, что эквивалентно записи:
default:
; // пустой оператор, не выполняющий
// никаких действий
Очевидно, что приведенный пример можно переписать с помощью оператора if:
if (code == 0) {
cout << "код ноль";
x = x + 1;
} else if (code == 1) {
cout << "код один";
y = y + 1;
} else if (code == 2) {
cout << "код два";
z = z + 1;
} else {
cout << "Необрабатываемое значение";
}
Пожалуй, запись с помощью оператора переключения switch более наглядна. Особенно часто переключатель используется, когда значение выражения имеет тип набора. :
4.6 Операторы цикла
Предположим, нам нужно вычислить сумму всех целых чисел от 0 до 100. Для этого воспользуемся оператором цикла for:
int sum = 0;
int i;
for (i = 1; i <= 100; i = i + 1)
// заголовок цикла
sum = sum + i; // тело цикла
Оператор цикла состоит из заголовка цикла и тела цикла. Тело цикла – это оператор, который будет повторно выполняться (в данном случае – увеличение значения переменной sum на величину переменной i). Заголовок – это ключевое слово for, после которого в круглых скобках записаны три выражения, разделенные точкой с запятой. Первое выражение вычисляется один раз до начала выполнения цикла. Второе – это условие цикла. Тело цикла будет повторяться до тех пор, пока условие цикла истинно. Третье выражение вычисляется после каждого повторения тела цикла.
Оператор for реализует фундаментальный принцип вычислений в программировании – итерацию. Тело цикла повторяется для разных, в данном случае последовательных, значений переменной i. Повторение иногда называется итерацией. Мы как бы проходим по последовательности значений переменной i, выполняя с текущим значением одно и то же действие, тем самым постепенно вычисляя нужное значение. С каждой итерацией мы подходим к нему все ближе и ближе. С другим принципом вычислений в программировании – рекурсией – мы познакомимся в разделе, описывающем функции.
Любое из трех выражений в заголовке цикла может быть опущено (в том числе и все три). То же самое можно записать следующим образом:
int sum = 0;
int i = 1;
for (; i <= 100; ) {
sum = sum + i;
i = i + 1;
}
Заметим, что вместо одного оператора цикла мы записали несколько операторов, заключенных в фигурные скобки – блок. Другой вариант:
int sum = 0;
int i = 1;
for (; ;) {
if (i > 100)
break;
sum = sum + i;
i = i + 1;
}
В последнем примере мы опять встречаем оператор break. Оператор break завершает выполнение цикла. Еще одним вспомогательным оператором при выполнении циклов служит оператор продолжения continue. Оператор continue заставляет пропустить остаток тела цикла и перейти к следующей итерации (повторению). Например, если мы хотим найти сумму всех целых чисел от 0 до 100, которые не делятся на 7, можно записать это так:
int sum = 0;
for (int i = 1; i <= 100; i = i+1) {
if ( i % 7 == 0)
continue;
sum = sum + i;
}
Еще одно полезное свойство цикла for: в первом выражении заголовка цикла можно объявить переменную. Эта переменная будет действительна только в пределах цикла.
Другой формой оператора цикла является оператор while. Его форма следующая:
while (условие)
оператор
Условие – как и в условном операторе if – это выражение, которое принимает логическое значение "истина" или "ложь". Выполнение оператора повторяется до тех пор, пока значением условия является true (истина). Условие вычисляется заново перед каждой итерацией. Подсчитать, сколько десятичных цифр нужно для записи целого положительного числа N, можно с помощью следующего фрагмента:
int digits = 0;
while (N > 0) {
digits = digits + 1;
N = N / 10;
}
Если число N меньше либо равно нулю, тело цикла не будет выполнено.
Третьей формой оператора цикла является цикл do while. Он имеет форму:
do { операторы } while ( условие);
Отличие от предыдущей формы цикла while заключается в том, что условие проверяется после выполнения тела цикла. Предположим, требуется прочитать символы с терминала до тех пор, пока не будет введен символ "звездочка".
char ch;
do {
ch = getch(); // функция getch возвращает
// символ, введёный с
// клавиатуры
} while (ch != '*');
В операторах while и do также можно использовать операторы break и continue.
Как легко заметить, операторы цикла взаимозаменяемы. Оператор while соответствует операторатору for:
for ( ; условие ; )
оператор
Пример чтения символов с терминала можно переписать в виде:
char ch;
ch = getch();
while (ch != '*') {
ch = getch();
}
Разные формы нужны для удобства и наглядности записи.
4.7 Оператор возврата
Оператор return завершает выполнение функции и возвращает управление в ту точку, откуда она была вызвана. Его форма:
return выражение;
Где выражение – это результат функции. Если функция не возвращает никакого значения, то оператор возврата имеет форму
return;
4.8 Оператор перехода
Последовательность выполнения операторов в программе можно изменить с помощью оператора перехода goto. Он имеет вид:
goto метка;
Метка ставится в программе, записывая ее имя и затем двоеточие. Например, вычислить абсолютную величину значения переменной x можно следующим способом:
if ( x >= 0)
goto positiv;
x = -x; // переменить знак x
positiv: // объявление метки
abs = x; // присвоить переменной abs
// положительное значение
При выполнении goto вместо следующего оператора выполняется оператор, стоящий после метки positiv. Если значение x положительное, оператор x = - x выполняться не будет.
В настоящее время считается, что оператор goto очень легко запутывает программу.Без него, вообще говоря, можно обойтись, поэтому лучше его не использовать, ну разве что лишь в самом крайнем случае.
Пример:
int fact(int n)
{
int k;
if (n == 1) {
k = 1;
} else {
k = n * fact(n – 1);
}
return k;
}
Это функция вычисления факториала. Первый оператор в ней – это объявление переменной k, в которой будет храниться результат вычисления. Затем выполняется условный оператор if. Если n равно единице, то вычисления факториала закончены, и выполняется оператор-выражение, который присваивает переменной значение 1. В противном случае выполняется другой оператор-выражение.
Последний оператор – это оператор возврата из функции.
Функции
5.1 Вызов функций
Функция вызывается при вычислении выражений. При вызове ей передаются определенные аргументы, функция выполняет необходимые действия и возвращает результат.
Программа на языке Си++ состоит, по крайней мере, из одной функции – функции main. С нее всегда начинается выполнение программы. Встретив имя функции в выражении, программа вызовет эту функцию, т.е. передаст управление на ее начало и начнет выполнять операторы. Достигнув конца функции или оператора return – выхода из функции, управление вернется в ту точку, откуда функция была вызвана, подставив вместо нее вычисленный результат.
Прежде всего, функцию необходимо объявить. Объявление функции, аналогично объявлению переменной, определяет имя функции и ее тип – типы и количество ее аргументов и тип возвращаемого значения.
// функция sqrt с одним аргументом –
// вещественным числом двойной точности,
// возвращает результат типа double
double sqrt(double x);
// функция sum от трех целых аргументов
// возвращает целое число
int sum(int a, int b, int c);
Объявление функции называют иногда прототипом функции. После того, как функция объявлена, ее можно использовать в выражениях:
double x = sqrt(3) + 1;
sum(k, l, m) / 15;
Если функция не возвращает никакого результата, т.е. она объявлена как void, ее вызов не может быть использован как операнд более сложного выражения, а должен быть записан сам по себе:
func(a,b,c);
Определение функции описывает, как она работает, т.е. какие действия надо выполнить, чтобы получить искомый результат. Для функции sum, объявленной выше, определение может выглядеть следующим образом:
int
sum(int a, int b, int c)
{
int result;
result = a + b + c;
return result;
}
Первая строка – это заголовок функции, он совпадает с объявлением функции, за исключением того, что объявление заканчивается точкой с запятой. Далее в фигурных скобках заключено тело функции – действия, которые данная функция выполняет.
Аргументы a, b и c называются формальными параметрами. Это переменные, которые определены в теле функции (т.е. к ним можно обращаться только внутри фигурных скобок). При написании определения функции программа не знает их значения. При вызове функции вместо них подставляются фактические параметры – значения, с которыми функция вызывается. Выше, в примере вызова функции sum, фактическими параметрами ( или фактическими аргументами) являлись значения переменных k, l и m.
Формальные параметры принимают значения фактических аргументов, заданных при вызове, и функция выполняется.
Первое, что мы делаем в теле функции — объявляем внутреннюю переменную result типа целое. Переменные, объявленные в теле функции, также называют локальными. Это связано с тем, что переменная result существует только во время выполнения тела функции sum. После завершения выполнения функции она уничтожается – ее имя становится неизвестным, и память, занимаемая этой переменной, освобождается.
Вторая строка определения тела функции – вычисление результата. Сумма всех аргументов присваивается переменной result. Отметим, что до присваивания значение result было неопределенным (то есть значение переменной было неким произвольным числом, которое нельзя определить заранее).
Последняя строчка функции возвращает в качестве результата вычисленное значение. Оператор return завершает выполнение функции и возвращает выражение, записанное после ключевого слова return, в качестве выходного значения. В следующем фрагменте программы переменной s присваивается значение 10:
int k = 2;
int l = 3;
int m = 5;
int s = sum(k, l, m);
5.2 Имена функций
В языке Си++ допустимо иметь несколько функций с одним и тем же именем, потому что функции различаются не только по именам, но и по типам аргументов. Если в дополнение к определенной выше функции sum мы определим еще одну функцию с тем же именем
double
sum(double a, double b, double c)
{
double result;
result = a + b + c;
return result;
}
это будет считаться новой функцией. Иногда говорят, что у этих функций разные подписи. В следующем фрагменте программы в первый раз будет вызвана первая функция, а во второй раз – вторая:
int x, y, z, ires;
double p,q,s, dres;
. . .
// вызвать первое определение функции sum
ires = sum(x,y,z);
// вызвать второе определение функции sum
dres = sum(p,q,s);
При первом вызове функции sum все фактические аргументы имеют тип int. Поэтому вызывается первая функция. Во втором вызове все аргументы имеют тип double, соответственно, вызывается вторая функция.
Важен не только тип аргументов, но и их количество. Можно определить функцию sum, суммирующую четыре аргумента:
int
sum(int x1, int x2, int x3, int x4)
{
return x1 + x2 + x3 + x4;
}
Отметим, что при определении функций имеют значение тип и количество аргументов, но не тип возвращаемого значения. Попытка определения двух функций с одним и тем же именем, одними и теми же аргументами, но разными возвращаемыми значениями, приведет к ошибке компиляции:
int foo(int x);
double foo(int x);
// ошибка – двукратное определение имени
5.3 Необязательные аргументы функций
При объявлении функций в языке Си++ имеется возможность задать значения аргументов по умолчанию. Первый случай применения этой возможности языка – сокращение записи. Если функция вызывается с одним и тем же значением аргумента в 99% случаев, и это значение достаточно очевидно, можно задать его по умолчанию. Предположим, функция expnt возводит число в произвольную целую положительную степень. Чаще всего она используется для возведения в квадрат. Ее объявление можно записать так:
double expnt (double x, unsigned int e = 2);
Определение функции:
double
expnt (double x, unsigned int e)
{
double result = 1;
for (int i = 0; i < e; i++)
result *= x;
return result;
}
int main()
{
double y = expnt(3.14);
double x = expnt(2.9, 5);
return 1;
}
Использовать аргументы по умолчанию удобно при изменении функции. Если при изменении программы нужно добавить новый аргумент, то для того чтобы не изменять все вызовы этой функции, можно новый аргумент объявить со значением по умолчанию. В таком случае старые вызовы будут использовать значение по умолчанию, а новые – значения, указанные при вызове.
Необязательных аргументов может быть несколько. Если указан один необязательный аргумент, то либо он должен быть последним в прототипе, либо все аргументы после него должны также иметь значение по умолчанию.
Если для функции задан необязательный аргумент, то фактически задано несколько подписей этой функции. Например, попытка определения двух функций
double expnt (double x, unsigned int e = 2);
double expnt (double x);
приведет к ошибке компиляции – неоднозначности определения функции. Это происходит потому, что вызов
double x = expnt(4.1);
подходит как для первой, так и для второй функции.
5.4 Рекурсия
Определения функций не могут быть вложенными, т.е. нельзя внутри тела одной функции определить тело другой. Разумеется, можно вызвать одну функцию из другой. В том числе функция может вызвать сама себя.
Рассмотрим функцию вычисления факториала целого числа. Ее можно реализовать двумя способами. Первый способ использует итерацию:
int
fact(int n)
{
int result = 1;
for (int i = 1; i <= n; i++)
result = result * i;
return result;
}
Второй способ:
int
fact(int n)
{
if (n == 1) // факториал 1 равен 1
return 1;
else // факториал числа n равен
// факториалу n-1
// умноженному на n
return n * fact(n -1);
}
Функция fact вызывает сама себя с модифицированными аргументами. Такой способ вычислений называется рекурсией. Рекурсия – это очень мощный метод вычислений. Значительная часть математических функций определяется в рекурсивных терминах. В программировании алгоритмы обработки сложных структур данных также часто бывают рекурсивными. Рассмотрим, например, структуру двоичного дерева. Дерево состоит из узлов и направленных связей. С каждым узлом могут быть связаны один или два узла, называемые сыновьями этого узла. Соответственно, для "сыновей" узел, из которого к ним идут связи, называется "отцом". Узел, у которого нет "отца", называется корнем. У дерева есть только один корень. Узлы, у которых нет "сыновей", называются листьями. Пример дерева приведен на рис. 5.1.
Рис. 5.1. Пример дерева.
В этом дереве узел A – корень дерева, узлы B и C – "сыновья" узла A, узлы D и E – "сыновья" узла B, узел F – "сын" узла C. Узлы D, E и F – листья. Узел B является корнем поддерева, состоящего из трех узлов B, D и E. Обход дерева (прохождение по всем его узлам) можно описать таким образом:
-
Посетить корень дерева.
-
Обойти поддеревья с корнями — "сыновьями" данного узла, если у узла есть "сыновья".
-
Если у узла нет "сыновей" — обход закончен.
Очевидно, что реализация такого алгоритма с помощью рекурсии не составляет труда.
Довольно часто рекурсия и итерация взаимозаменяемы (как в примере с факториалом). Выбор между ними может быть обусловлен разными факторами. Чаще рекурсия более наглядна и легче реализуется. Кроме того, в большинстве случаев итерация более эффективна.
6 Встроенные типы данных
6.1 Общая информация
Встроенные типы данных предопределены в языке. Это самые простые величины, из которых составляют все производные типы, в том числе и классы. Различные реализации и компиляторы могут определять различные диапазоны значений целых и вещественных чисел.
В таблице 6.1 перечислены простейшие типы данных, которые определяет язык Си++, и приведены наиболее типичные диапазоны их значений.
Таблица 6.1. Встроенные типы языка Си++.
|
Название
|
Обозначание
|
Диапазон значений
|
Байт
|
char
|
от -128 до +127
|
Байт без знака
|
unsigned char
|
от 0 до 255
|
Короткое целое число
|
short
|
от -32768 до +32767
|
Короткое целое число без знака
|
unsigned short
|
от 0 до 65535
|
Целое число
|
int
|
от – 2147483648 до + 2147483647
|
Целое число без знака
|
unsigned int (или просто unsigned)
|
от 0 до 4294967295
|
Длинное целое число
|
long
|
от – 2147483648 до + 2147483647
|
Длинное целое число
|
unsigned long
|
от 0 до 4294967295
|
Вещественное число одинарной точности
|
float
|
от ±3.4e-38 до ±3.4e+38 (7 значащих цифр)
|
Вещественное число двойной точности
|
double
|
от ±1.7e-308 до ±1.7e+308 (15 значащих цифр)
|
Вещественное число увеличенной точности
|
long double
|
от ±1.2e-4932 до ±1.2e+4932
|
Логическое значение
|
bool
|
значения true (истина) или false (ложь)
|
Достарыңызбен бөлісу: |