книги / Практикум по программированию на языке Си
..pdfРуководства по технологии программирования настойчиво рекомендуют избегать хаотического, стихийного использования перечисленных операторов. Профессиональный стиль программирования предполагает следование принципам структурного программирования и применение нисходящего поэтапного конструирования алгоритмов. При этом каждое действие, предусматриваемое в программе, может быть представлено (детализировано) либо линейной последовательностью более элементарных действий, либо конструкцией ветвления (выбора варианта), либо циклом.
Линейная последовательность действий представляется в языке Си либо составным оператором, либо блоком. Отличие между ними в наличии определений и описаний в начале каждого блока. Пример блока приведен в программе 04_05.с (тема 4).
5.1. Условный оператор
Сокращенная форма условного оператора: if (условие) оператор;
Полная форма условного оператора:
if (условие) оператор1; else оператор2;
Здесь условие, называемое также управляющим выражением, – логическое или арифметическое выражение. Каждый из операторов может быть либо отдельным оператором, либо блоком, либо составным оператором.
ЗАДАЧА 05-01. Введите три целых числа и выведите на печать (на экран дисплея) минимальное из введенных значений. Используйте для решения условные операторы.
Следующая программа решает задачу:
/* 05_01.c - минимум из трех значений. Условный оператор */
#include <stdio.h> #define READI(VARIABLE) \
{printf(#VARIABLE"="); scanf("%d",&VARIABLE);} int main ()
{
int x, y, z, res;
131
READI(x);
READI(y);
READI(z);
res=x;
if (res > y) res=y; if (res > z) res=z;
printf("min=%d", res); return 0;
}
Результат выполнения программы:
x=16<ENTER>
y=38<ENTER>
z=9<ENTER>
min=9
В программе дважды применен сокращенный условный оператор, в котором в качестве управляющего выражения использовано отношение (логическое выражение).
ЗАДАНИЕ. В данном примере применение условного оператора может быть исключено, если воспользоваться условным (тернарным) выражением. Решите задачу: 1) используя два условных (тернарных) выражения; 2) используя сложное выражение, включающее две тернарные операции. (Особенности тернарных выражений рассмотрены в предыдущей теме.)
ЗАДАЧА 05-02. Введите целое число и проверьте его одновременную кратность двум другим целым числам, также вводимым с клавиатуры. В качестве проверяемого условия в условном операторе примените арифметическое выражение.
Задачу решает следующая программа:
/* 05_02.c - арифметическое выражение в качестве условия */
#include <stdio.h> #define READI(VARIABLE) \
{printf(#VARIABLE"="); scanf("%d",&VARIABLE);} int main ()
{
132
int number,a,b; READI(number); READI(a); READI(b);
if (number%a)
puts("Not divisible!"); else
if (number%b)
puts("Not divisible!"); else
puts("Divisible!"); return 0;
}
Результаты выполнения программы:
number=87 <ENTER> a=3<ENTER> b=5<ENTER>
Not divisible!
Результаты второго выполнения программы:
number=75 <ENTER> a=5<ENTER> b=3<ENTER> Divisible!
(По-английски divisible – делящийся без остатка.)
ЗАДАНИЕ. Замените арифметические управляющие выражения в операторе if логическими выражениями.
ЗАДАЧА 05-03. Ввести три целых числа и вывести их на печать (на экран дисплея) в порядке возрастания.
Задачу решает следующая программа:
/* 05_03.c - упорядочение трех значений */ #include <stdio.h>
#define READI(VARIABLE) \
{printf(#VARIABLE"="); scanf("%d",&VARIABLE);}
133
#define PRINTI(EXPRESSION) \ printf(#EXPRESSION"=%d\n",EXPRESSION)
int main ()
{
int x, y, z, res; READI(x); READI(y); READI(z);
printf("Result:\n"); if (x > y)
if (y > z)
{PRINTI(z); PRINTI(y); PRINTI(x); }
else
{PRINTI(y);
if (x > z) { |
PRINTI(z); |
PRINTI(x); |
} |
|
else |
{ |
PRINTI(x); |
PRINTI(z); |
} |
}
else
if (x > z)
{PRINTI(z); PRINTI(x); PRINTI(y); }
else
{PRINTI(x);
if (y > z) { PRINTI(z); PRINTI(y); }
else |
{ PRINTI(y); PRINTI(z); } |
} |
|
return 0; |
|
}
Результат выполнения программы:
x=3<ENTER>
y=44<ENTER>
z=15<ENTER>
Result:
x=3
z=15
y=44
Зачастую для решения одной и той же задачи можно использовать разные средства языка. В качестве примера рассмотрим классическую задачу вычисления корней квадратного уравнения:
134
ax2 + bx +c = 0
Известно, что при разных значениях коэффициентов a, b, c задача вычисления корней должна решаться по разным правилам. Перечислим возможные варианты:
a==0, b==0, c==0 – неопределенное решение; a==0, b==0, c!=0 – противоречие;
a==0, b!=0, c==0 – нулевое решение, один корень; a==0, b!=0, c!=0 – линейное уравнение, один корень; a!=0, b×b–4×a×c>=0 – два действительных корня; a!=0, b×b–4×a×c<0 – два комплексных корня.
В случаях, когда а!=0 справедлива формула:
x |
= |
− |
b |
± |
b2 − 4ac |
. |
1,2 |
|
2a |
|
4a2 |
|
|
|
|
|
|
С ее помощью при положительном дискриминанте b2 − 4ac > 0 вычисляются два действительных корня. При отрицательном дис-
криминанте, т.е. когда b2 − |
4ac < |
0 , |
комплексные корни можно |
||
определить так: |
|
|
|
|
|
− |
b |
b2 − |
4ac |
, |
|
x1,2 = 2a ± i |
4a2 |
||||
|
где i – мнимая единица.
Отметим, что в языке Си комплексную величину можно представить двумя переменными, соответствующими ее действительной и мнимой частям.
ЗАДАЧА 05-04. Составьте программу для решения квадратного уравнения в соответствии с приведенными соотношениями. Исходные данные – значения коэффициентов a, b, c, вводимые пользователем с клавиатуры.
Для решения задачи можно написать программы с разными операторами управления последовательностью вычислений. Например, в следующей программе используются сокращенные условные операторы и операторы return.
135
/* 05_04.c – решение квадратного уравнения
(if + return) */ #include <stdio.h>
#include <math.h>
#define READD(VARIABLE) \
{printf(#VARIABLE"="); scanf("%le",&VARIABLE);} int main ()
{
double a, b, c, discri, di_sqr, abs_di_sqr; READD(a);
READD(b);
READD(c);
if (a == 0.0 && b == 0.0 && c == 0.0)
{printf("The undefined solution!"); return 0;
}
if (a == 0.0 && b == 0.0 && c != 0.0) { printf("The contradiction!");
return 0;
}
if (a == 0.0 && b != 0.0 && c == 0.0) { printf("The solution: x=%f", 0.0);
return 0;
}
if (a == 0.0 && b != 0.0 && c != 0.0)
{printf("The solution: x=%f", -c/b); return 0;
}
discri = b*b - 4*a*c;
if (a != 0.0 && discri >= 0.0)
{di_sqr=sqrt(discri); printf("The solution: x1=%f",
-b/(2*a)+di_sqr/(2*a)); printf("\n x2=%f",
-b/(2*a)-di_sqr/(2*a)); return 0;
}
if (a != 0.0 && discri < 0.0)
{abs_di_sqr=sqrt(fabs(discri)); printf("The solution: x1=%f + i%f",
-b/(2*a),abs_di_sqr/(2*a)); printf("\n x2=%f - i%f",
136
-b/(2*a),abs_di_sqr/(2*a)); return 0;
}
}
Результаты выполнения программы c разными данными.
Первое исполнение:
a=0<ENTER>
b=0<ENTER>
c=0<ENTER>
The undefined solution!
Второе исполнение:
a=0<ENTER>
b=0<ENTER> c=-15<ENTER>
The contradiction!
Третье исполнение:
a=0<ENTER>
b=40<ENTER>
c=0<ENTER>
The solution: x=0.000000
Четвертое исполнение:
a=0<ENTER>
b=12<ENTER>
c=6<ENTER>
The solution: x=-0.500000
Пятое исполнение:
a=2<ENTER> b=-1<ENTER> c=-6<ENTER>
The solution: x1=2.000000 x2=-1.500000
137
Шестое исполнение:
a=34<ENTER>
b=4<ENTER>
c=2<ENTER>
The solution: x1=-0.058824 + i0.235294 x2=-0.058824 - i0.235294
ЗАДАНИЕ. Составьте программу для решения той же задачи, используя полные условные операторы и только один опера-
тор return.
ЗАДАЧА 05-05. Ввести время суток в виде целого числа от 0 до 24, напечатать соответствующее времени английское приветствие:
22 – 3 – Good Night!
4 – 10 – Good Morning!
11 – 14 – Good Day!
15 – 16 – Good Afternoon!
17 – 21 – Good Evening!
Вариант 1. Использовать сокращенный условный оператор. Вариант 2. Использовать сокращенный условный оператор и
операторы return, прерывающие исполнение программы при нахождении нужного условия.
Вариант 3. Использовать вложение полных условных операторов.
Вариант 2 реализует следующая программа:
/* 05_05.c - английские приветствия (if + return) */ #include <stdio.h>
int main ()
{int time;
printf("Print time (from 0 to 24): "); scanf("%d",&time);
if (time>=22 && time<=24 || time<4 && time>=0)
{puts("Good Night!");
return 0;
}
if (time >= 4 && time < 11)
138
{puts("Good Morning!"); return 0;
}
if (time >= 11 && time < 15)
{puts("Good Day!"); return 0;
}
if (time >= 15 && time < 17) { puts("Good Afternoon!");
return 0;
}
if (time >= 17 && time < 22)
{puts("Good Evening!"); return 0;
}
puts("Error!!!"); return 0;
}
Результат выполнения программы:
Print time (from 0 to 24): 20<ENTER>
Good Evening!
Вариант 3 может быть реализован по аналогии с программой, решающей следующую задачу.
ЗАДАЧА 05-06. Испытуемый при тестировании может получить некоторое количество очков от 0 до 100. По результатам тестирования выставляется оценка в баллах:
от 0 до 20 – 2 балла; от 21 до 40 – 3 балла; от 41 до 80 – 4 балла; от 81 до 100 – 5 баллов.
Ввести количество очков тестирования, вывести соответствующий балл.
Как и в задаче 05-05, с помощью условных операторов возможны три варианта решения. Следующая программа реализует вариант с вложением полных условных операторов.
139
/* 05_06.c - очки тестирования и оценки в баллах */ #include <stdio.h>
int main ()
{
int testPoints;
printf("Input points (from 0 to 100): "); scanf("%d",&testPoints);
if (testPoints >= 0 && testPoints < 21) puts("The mark is 2!");
else
if (testPoints >= 21 && testPoints < 41) puts("The mark is 3!");
else
if (testPoints >= 41 && testPoints < 81) puts("The mark is 4!");
else
if (testPoints >= 81 && testPoints < 101) puts("The mark is 5!");
else puts("Error!!!");
return 0;
}
Результат первого выполнения программы:
Input points (from 0 to 100): -12<ENTER> Error!!!
Результат второго выполнения программы:
Input points (from 0 to 100): 47<ENTER>
The mark is 4!
5.2. Переключатели (switch)
Применение переключателей (оператор switch) наиболее целесообразно в том случае, когда ветвления нужно выполнить на основе сравнения значения некоторого выражения (например, переменной) с фиксированным набором значений. Часто это удобно при программировании меню. В качестве упражнения рассмотрим следующую задачу, в некотором смысле обратную 05-05 и 05-06.
140