- •Ввод и вывод числовых значений
- •Логические выражения
- •Знаки отношения
- •Логические операции
- •Построение циклов при помощи условных операторов
- •Оператор цикла for
- •Оператор цикла с постусловием
- •Лабораторная работа №5. Составить программу, выполняющую суммирование ряда:
- •Типы данных
- •Целые числа
- •Вещественные числа
- •Символы
- •Массивы
- •Двумерные массивы
Ввод и вывод числовых значений
Программы, выполняющие вывод арифметических выражений, содержащих только константы (без использования переменных), обладают очевидным недостатком. Они рассчитаны на одноразовое действие; вычисляют значения только некоторых фиксированных выражений. В принципе, можно вносить изменения в эти выражения и получать новые значения, однако это означает непосредственную работу с текстом программы, что доступно только ее автору или другим квалифицированным программистам и недоступно для пользователей, которые должны получать готовую к работе программу, а не нуждающийся в постоянных корректировках текст программы.
Для устранения такого недостатка нужно выполнить следующее. Во-первых, в арифметических выражениях использовать не только константы, но и переменные. Во-вторых, описать эти переменные в программе. И в-третьих, использовать операторы ввода значений этих переменных.
Рассмотрим эти три задачи. Предположим, что мы желаем вычислить целочисленное значение выражения:
2*i+3*j–7
с использованием значений целочисленных переменных i и j, а также вещественное значение выражения:
с использованием значений тех же переменных i и j, а также вещественных переменных x и y.
В программе можно использовать только те переменные, которые предварительно описаны. В данном случае описание на языке С++ выглядит так:
int i,j;
double x,y;
Это описание, в данном случае, поставим после открывающей фигурной скобки.
На языке С++ это делается совсем просто при помощи оператора:
cin >> i >> j >> x >> y;
Учитывая, что дальнейший текст программы очевиден, приведем его полностью:
#include<iostream.h>
void main()
{
int i,j;
double x,y;
cin >> i >> j >> x >> y;
cout << 2*i+3*j-7 << "\n" << (i+j)/(x-y) << "\n";
}
После запуска этой программы она будет ожидать ввода величин, указанных в операторе cin. Значения величин набираются вручную программистом и отделяются друг от друга пробелами. Затем нажимается клавиша Enter, программа производит соответствующие вычисления и выдает результаты при помощи оператора cout. Вначале выводится значение выражения 2*i+3*j-7, затем пробел (заданный строкой " "), затем значение выражения (i+j)/(x-y), после чего производится перевод на новую строку с помощью символов "\n".
После очередного нажатия клавиши Enter программа заканчивает работу. Но ее можно тут же запустить вновь и выполнить расчеты с использованием новых значений переменных.
Программа на С++ в консольном варианте является несложной, но и не очень удобной. В частности, при повторном ее запуске вы не видите значений переменных, использованных при предыдущем просчете.
Лабораторная работа №1.
Придумать какие-нибудь достаточно громоздкие формулы и составить программу на С++ для выполнения вычислений по этим формулам.
В заключение этого раздела рассмотрим еще один вопрос. Он связан с переносом на новую строку в длинных арифметических выражениях. Известны правила такого переноса в обычных формулах. Последний знак операции в предыдущей строке повторяется как первый знак в новой строке:
x+y–z+a+
+c–12
Однако, при программировании это делать не рекомендуется. В самом деле, запись:
x+y–z+a+
+c–12
в программе будет означать, что знак + между а и с повторился дважды, поскольку перенос на новую строку программой игнорируется.
Рекомендуется записывать перенос формулы так:
x+y–z+a+
c–12
либо так:
x+y–z+a
+c–12,
т.е. записывать знак операции (любой) только один раз.
Это правило дает надежные результаты, но все же возможны отступления от него, например, в результате случайной описки. Оказывается, что транслятор пропускает арифметические выражения, в которых повторяются подряд несколько одинаковых или разных знаков операции. Но в этом случае результат вычислений будет труднопредсказуемым.
В качестве самостоятельного упражнения предлагается поэкспериментировать с данным вопросом, т.е. записывать формулы, в которых между двумя операндами стоят по несколько знаков и проверять результаты вычислений.
ОСНОВНЫЕ ОПЕРАТОРЫ
Введение
Любая программа состоит из последовательности операторов. Операторы могут выполняться либо в естественном порядке их записи, либо в каком-то другом порядке, указанном в них. Рассмотрим основные виды операторов.
Оператор присваивания
До сих пор, вычислив значение какого-то арифметического выражения, мы немедленно выводили результат. Однако, чаще всего, результаты каких-то вычислений используются в дальнейших вычислениях, поэтому нет необходимости выводить такие промежуточные результаты; важнее передать их каким-то переменным. Такая передача результатов вычислений каким-то переменным выполняется в так называемых операторах присваивания.
В языке C++ операторы присваивания будут иметь вид:
y=2*x;
k=i-j;
gamma=(alpha+3.89*beta)*(2*sigma-delta)/6.44-25;
Иначе говоря, ставится просто знак =. Считается, что программист, обладая достаточной квалификацией, не спутает знак равенства с оператором присваивания. Хотя, разумеется, операторы типа:
i=i+7;
x=2*x;
в С на первый взгляд выглядят странно. Т.е. мы должны помнить, что речь идет не о равенстве (хотя и использован математический знак равенства), а о передаче информации, о чем речь шла выше.
В С возможно множественное присваивание. Например, если вы хотите присвоить одно и то же значение нескольким переменным, это выполняется одним оператором:
i=j=2;
Вообще в С предпочитают говорить не об операторе присваивания, а об операции присваивания. Это связано с тем, что такая операция может появиться в самых, на первый взгляд, неожиданных местах. Например, присвоить какое-то значение можно переменной, входящей в состав формулы:
x=2*(y=3);
Здесь вначале переменная y получает значение, равное 3, и только после этого производится умножение, и переменная x получает свое значение (6). Считается более предпочтительным писать так:
y=3;
x=2*y;
Это связано с требованием максимальной наглядности программы; избежания, по возможности, ситуаций, которые могут приводить к ошибкам.
Тем не менее, в С различные совмещения очень популярны. Рассмотрим некоторые из них. Вместо оператора:
x=x+1;
можно писать:
x++;
или:
++x;
с теми же результатами. Именно наличие этих операторов привело к изменению названия С на С++.
Можно писать и так:
x=2;
y=2*x++;
В этом случае вначале переменная x получит значение 2, что выполняется в первом оператора присваивания; второй оператор выполняет сразу два присваивания. Вначале значение x будет умножено на 2 и результат будет присвоен переменной y, которая после этого станет равной 4, а затем переменная x получит приращение на единицу и станет равной 3.
Если записать:
x=2;
y=2*++x;
то последовательность действий и результаты будут другими. Во втором операторе вначале переменная x получит приращение на единицу, т.е. станет равной 3, и только после этого это ее новое значение будет умножено на 2, и переменная y получит значение 6.
Переменная x в обоих случаях получает значение 3, а переменная y в одном случае получает значение 4, а во втором – 6.
Аналогично, эквивалентными являются операторы:
x=x-1;
x--;
--x;
Операторы:
x=2;
y=2*x--;
приведут к значениям x=1, y=4; а операторы:
x=2;
y=2*--x;
– к значениям x=1, y=2.
Отметим еще несколько характерных для С++ совмещений операций: Оператор:
x+=2;
эквивалентен оператору:
x=x+2;
Аналогично выполняется оператор:
x-=3;
эквивалентный оператору:
x=x-3;
и операторы:
x*=3;
x/=4;
эквивалентные операторам:
x=x*3;
x=x/4;
Мы увидели, что даже самый простой из операторов – оператор присваивания – обладает своими особенностями и требует определенных навыков при его применении. Особенно это относится к оператору присваивания в языке С++. Поэтому рекомендуется, по крайней мере, на первых порах, писать программы на С++, не используя совмещения операций. Это связано, в первую очередь, с тем, что в современном программировании главное внимание уделяется надежности программ, а не компактности записи их текста. Как правило, предпочтительными являются те конструкции, которые делают программы более наглядными и, как следствие, менее уязвимыми для ошибок. Разумеется, выполнение этой рекомендации существенно зависит от квалификации программиста. То, что кажется запутанным для одного программиста, будет совершенно ясным для другого.
Однако, чрезмерно усложненные конструкции могут запутать и самого опытного программиста. Главным является то, чтобы программист писал языковые конструкции так же естественно, как он применяет конструкции своего родного языка, не задумываясь каждый раз над смыслом написанного.
Остановимся, в заключение этого параграфа, на согласовании типов левой и правой части оператора присваивания. Этот вопрос очевиден тогда, когда данные типы одинаковы.
При использовании языка С перевод как целых чисел в вещественные, так и вещественных чисел в целые производится автоматически. Правильными будут операторы:
x=i+j;
i=x-2.5;
Во втором из них произойдет автоматическое преобразование вещественного результата в целый с соответствующим округлением. Однако сделанные выше предупреждения об опасностях неконтролируемого перевода из вещественного типа в целый имеют силу и здесь. Поэтому и в языке С рекомендуют преобразования типов выполнять в явном виде:
i=(int)(x-2.5);
Ранее указывалось, что деление целочисленных величин в С производится с отбрасыванием дробной части, т.е. с сохранением целочисленности результата. Например, операторы:
i=1;
j=2;
x=i/j;
дадут значение x, равное нулю. И здесь полезным может быть явное преобразование типа. Правильным будет такая запись последнего оператора:
x=(float)i/j;
Название функции преобразования берется в скобки; она относится только к ближайшему операнду, в данном случае, к i. Вначале величина i преобразуется к вещественному типу, а затем выполняется деление, которое теперь приведет к правильному результату x=0.5. Если записать:
x=(float)(i/j);
то преобразование будет относиться ко всей дроби i/j, но результат будет вновь равным нулю, поскольку преобразование производится после целочисленного деления, дающего здесь нулевой результат.
Лабораторная работа № 2. Выполнить вычисления по придуманным самостоятельно формулам, используя оператор присваивания и операторы ввода-вывода. В программе на языке С++ применять характерные для С++ совмещения действий.
Оператор перехода
Существует оператор, который входит во все современные языки программирования. Это оператор goto. С его помощью прерывают естественный порядок выполнения операторов.
Оператор goto в языке С++ выглядит так : метка может быть только идентификатором, но не числом и не требует описания. Например:
#include<iostream.h>
void main()
{
int i,j;
double x,y;
i=3;
j=11;
goto a;
x=1.77;
y=66.33;
a: cout << j << "\n";
}
Не рекомендуется использовать оператор goto, если можно заменить его использованием любого цикла.
Условный оператор
До сих пор мы составляли программы, фактически, «одноразового» действия. При заданных исходных данных такие программы выполняли все операторы ровно по одному разу в строго определенном порядке (с учетом, если он есть, оператора goto). Подобный способ составления программ практически исключает возможность реализации какого-либо алгоритма.
Любой алгоритм предполагает анализ результатов производимых вычислений и выполнение дальнейших вычислений в зависимости от этих результатов. Иначе говоря, необходимо иметь возможность прерывать естественную последовательность операций, но не так, как было показано только что, а в зависимости от каких-то условий. Для этой цели служит условный оператор. Рассмотрим различные его разновидности, начиная с простейших.
Предположим, что требуется найти модуль некоторого числа x. Соответствующие действия изобразим графически в виде блок-схемы, изображенной на рис.1.
Рис. 1.
Последовательность действий, изображенная на рис. 1, достаточно очевидна, однако ее невозможно непосредственно отобразить в программе, поскольку блоки расположены не в линейном порядке. Преобразуем блок-схему к форме, изображенной на рис. 2. Теперь видно, что данной блок-схеме может отвечать следующая программа на C:
if (x>0) goto a;
modx=-x;
goto b;
a: modx=x;
b: ...
Эта, несложная по существу, программа хорошо демонстрирует нелюбовь программистов к оператору goto. Взаимодействие операторов:
modx=-x;
и
modx=x;
осуществляется путем «перепрыгивания» их друг через друга, что ненаглядно и легко может привести к ошибкам.
Рис. 2.
Гораздо естественнее записать то же самое в форме:
if (x>0) modx=x; modx=-x;
Результат получился значительно нагляднее и компактнее.
Мы привели полную форму условного оператора на С. Существует и сокращенная форма. Можно, например, записать:
modx=x;
if (x<0) modx=-x;
Эта форма несимметричная. Приоритет как бы отдается положительным значениям х, в связи с чем первоначально обязательно выполняется оператор:
modx=x;
Только затем выполняется проверка знака х и, при необходимости, выбирается другое значение переменной modx. Если же величина х действительно положительная, то условный оператор пропускается.
Мы рассмотрели на примерах две формы условного оператора на С++: неполную
if (<условие>) <оператор>;
и полную
if (<условие>) <оператор1>;<оператор2>;
В неполной форме проверяется условие; если оно справедливо, выполняется оператор, следующий за условием, если нет, то условный оператор пропускается и выполняется оператор, следующий за ним по порядку.
В полной форме также проверяется условие; если оно справедливо, выполняется оператор, следующий за условием, если нет, выполняется оператор, следующий за словом else. В обоих случаях далее выполняется оператор, стоящий вслед за условным, а проверяемое условие обязательно берется в скобки. Кроме того, оператор, стоящий перед, else заканчивается знаком «; » .
Построение блок-схем, подобных приведенным выше, при использовании современных форм условных операторов практически не требуется. Решим еще одну несложную задачу, на этот раз уже без предварительного построения блок-схемы.
Пусть требуется найти максимальное из двух чисел: x и y. Это выполняется при помощи оператора:
if (x>y) max=x; max=y;
И в этом случае мы обошлись без применения оператора goto, построив компактную и наглядную программу.
В рассмотренных примерах после условия и после else стояло ровно по одному оператору. С формальной точки зрения условный оператор if и рассчитан на это. Но как быть, если требуется поставить после условия и после else несколько операторов? Например, мы составляем программу поиска корней квадратного уравнения:
Известно, что вначале следует вычислить дискриминант:
,
а затем, если дискриминант положителен, найти два действительных корня:
,
а если отрицателен – действительную и мнимую части комплексных сопряженных корней:
В обоих случаях нужно найти по два числа, т.е. выполнить, по меньшей мере, по два оператора. С помощью оператора goto эта задача решается сравнительно легко:
D=b*b-4*a*c;
if (D>0) goto a;
Rex=-b/2/a;
Imx=sqrt(-D)/2/a;
cout << "x=" << Rex << "+" << Imx <<"i\n";
goto b;
a: x1=(-b+sqrt(D))/2/a;
x2=(-b-sqrt(D))/2/a;
cout << "x1=" << x1 << " x2=" << x2 <<"\n";
b:
Однако приведенная программа обладает тем же очевидным недостатком, что и все программы, в которых злоупотребляют оператором goto, т.е. ненаглядностью и, как следствие, возможностью допущения случайных ошибок.
Для того, чтобы избежать злоупотреблений оператором goto, поступим следующим образом. Объединим несколько операторов в один, взяв и в скобки. Это похоже на то, как берут в скобки несколько слагаемых, но здесь скобки называются операторными и обозначаются { и }. Ранее такие скобки уже использовались, но они обозначали начало и конец главной функции.
Теперь программа может выглядеть следующим образом:
D=b*b-4*a*c;
if (D<0)
{
Rex=-b/2/a;
Imx=sqrt(-D)/2/a;
cout << "x=" << Rex << "+" << Imx <<"i\n";
}
{
x1=(-b+sqrt(D))/2/a;
x2=(-b-sqrt(D))/2/a;
cout << "x1=" << x1 << " x2=" << x2 <<"\n";
}
После условия идут несколько операторов, которые воспринимаются условным оператором как один благодаря их помещению между фигурными скобками { и }; аналогично объединяются в один и три оператора, следующие вслед за словом else. Отметим, что в этом случае, т.е. после закрывающей операторной скобки, точка с запятой перед else не ставится.
Разумеется, и в этом случае отказ от оператора goto позволил резко увеличить наглядность программы. Если на ранних стадиях развития программистской науки и практики перед написанием программы почти всегда составляли блок-схемы типа приведенных выше, то теперь, благодаря удобствам, предоставляемым современными языками программирования, необходимость в составлении блок-схем почти полностью исчезла; по крайней мере, это относится к относительно несложным ситуациям типа рассмотренных здесь.
Лабораторная работа № 3. Составить на С++ программу с использованием условных операторов, взяв за пример представленные образцы. Оформить программы в законченном виде, пригодном для массовой эксплуатации.
