книги / Практикум по программированию на языке Си
..pdfЗАДАЧА 05-07. Выведите на экран список вида:
1 – night;
2 – morning;
3 – day;
4 – afternoon;
5 – evening. ֽ
Вводя номер пункта списка, напечатайте временные пределы, ограничивающие соответствующее время суток: 22–3 (night); 4–
10 (morning); 11–14 (day); 15–16 (afternoon); 17–21 (evening).
/* 05_07.c - время суток (switch...break) */ #include <stdio.h>
int main ()
{
int item;
puts("1. Night;"); puts("2. Morning;"); puts("3. Day;"); puts("4. Afternoon;"); puts("5. Evening.");
puts("Print item number:"); scanf("%d",&item);
switch(item)
{ case 1: puts("From 22 to 3 - Night"); break;
case 2: puts("From 4 to 10 - Morning"); break;
case 3: puts("From 11 to 14 - Day"); break;
case 4: puts("From 15 to 16 - Afternoon"); break;
case 5: puts("From 17 to 21 - Evening"); break;
default: puts("Error!");
}
return 0;
}
Результаты выполнения программы.
Первое исполнение:
1.Night;
2.Morning;
141
3.Day;
4.Afternoon;
5.Evening.
Print item number: 3<ENTER>
From 11 to 14 - Day
Второе исполнение:
1.Night;
2.Morning;
3.Day;
4.Afternoon;
5.Evening.
Print item number: 7<ENTER>
Error!
ЭКСПЕРИМЕНТ. Удалите из программы все операторы break. После трансляции введите не последний номер списка и объясните результат.
Чтобы использовать переключатель для ветвления по условию с проверкой попадания некоторой величины в тот или иной интервал, можно воспользоваться условным выражением, формирующим целочисленный номер соответствующего интервала.
ЗАДАЧА 05-08. Реализуйте указанный подход (переключатель с номером варианта) для печати английского приветствия:
Часы суток |
Номер интервала |
Приветствие |
|
22 |
– 3 |
интервал 1 |
Good Night! |
4 – 10 |
интервал 2 |
Good Morning! |
|
11 |
– 14 |
интервал 3 |
Good Day! |
15 |
– 16 |
интервал 4 |
Good Afternoon! |
17 |
– 21 |
интервал 5 |
Good Evening! |
Задачу решает следующая программа:
/* 05_08.c - английские приветствия (swith + номер варианта:) */
142
#include <stdio.h> int main ()
{
int time;
printf("Print time (from 0 to 24): "); scanf("%d",&time);
switch(time<0 ? 0: time<4 ? 1: time<11 ? 2: time<15 ? 3: time<17 ? 4: time<22 ? 5: time<24 ? 1:0)
{ case 1: puts("Good Night!"); break;
case 2: puts("Good Morning!"); break;
case 3: puts("Good Day!"); break;
case 4: puts("Good Afternoon!"); break;
case 5: puts("Good Evening!"); break;
default: puts("Error!");
}
return 0;
}
Результат первого выполнения программы:
Print time (from 0 to 24): 20<ENTER>
Good Evening!
Результат второго выполнения программы:
Print time (from 0 to 24): 30<ENTER>
Error!
ЗАДАНИЕ. Исключите условное выражение из переключателя в программе 05_08.с.
В соответствии со смыслом задачи и целочисленностью переменной time (используются только часы, минуты не учитываются)
143
каждому интервалу соответствует конечное и не слишком большое количество значений. Их можно явно использовать в виде констант, входящих в case. Таким образом, решение может быть следующим:
// 05_08_1.c - несколько меток ветви переключателя
#include <stdio.h> int main ()
{
int time;
printf("Print time (from 0 to 24): "); scanf("%d",&time);
switch(time)
{case 22: case 23: case 24:
case 0: case 1: case 2: case 3: puts("Good Night!"); break;
case 4: case 5: case 6: case 7: case 8: case 9: case 10:
puts("Good Morning!"); break;
case 11: case 12: case 13: case 14: puts("Good Day!");
break; case 15: case 16:
puts("Good Afternoon!"); break;
case 17: case 18: case 19: case 20: case 21: puts("Good Evening!");
break;
default: puts("Error!");
}
return 0;
}
Результат первого выполнения программы:
Print time (from 0 to 24): 20<ENTER>
Good Evening!
Результат второго выполнения программы:
Print time (from 0 to 24): 12<ENTER>
Good Day!
144
При использовании переключателя нужно не забывать следующие обязательные условия:
!управляющее выражение должно формировать целочисленное значение;
!после case (в метке варианта) может находиться только целочисленная константа (константное выражение);
!целочисленные константы, определяющие ветви одного переключателя, должны быть различны.
Придумать эксперимент, нарушающий приведенные правила.
5.3. Операторы циклов
ЗАДАЧА 05-09. Вводите целые числа и вычислите сумму положительных и сумму отрицательных чисел. Окончание работы – ввод нулевого числа.
Задачу решает следующая программа:
/* 05_09.c - суммы положительных и отрицательных чисел */
#include <stdio.h> #define READI(VARIABLE) \
{ printf(#VARIABLE"="); scanf("%d",&VARIABLE); } #define PRINTI(EXPRESSION) \
printf(#EXPRESSION"=%d\n",EXPRESSION) int main ()
{
int x, sumPlus=0, sumMinus=0; do { READI(x);
if (x < 0) sumMinus+=x;
else sumPlus+=x;
}
while(x != 0); PRINTI(sumPlus); PRINTI(sumMinus); return 0;
}
145
Результат выполнения программы:
x=2<ENTER>
x=55<ENTER> x=-9<ENTER> x=6<ENTER> x=-23<ENTER> x=7<ENTER> x=0<ENTER> sumPlus=70 sumMinus=-32
В программе использован оператор цикла с постусловием.
ЗАДАНИЕ. Напишите программу для решения рассмотренной задачи с применением:
1) оператора цикла с предусловием (оператор while);
2) оператора параметрического цикла (оператор for).
Соответствующие программы 05_09_1.с и 05_09_2.с есть в электронном виде, но мы не стали приводить здесь их тексты из-за их простоты.
ЗАДАЧА 05-10. Введя значения двух целых чисел n и k, вычислить и напечатать (в три столбца) значения i, i2, i3, где i = n, k .
Задачу решает следующая программа:
/* 05_10.c - числа, их квадраты и кубы */ #include <stdio.h>
#define READI(VARIABLE) \
{printf(#VARIABLE"="); scanf("%d",&VARIABLE);} int main ()
{int i, n, k; READI(n); READI(k);
for (i=n; n<=k ? i<=k:i>=k; i += n <= k ? 1: -1) printf("\n%d\t%d\t%d",i,i*i,i*i*i);
return 0;
}
146
Результаты выполнения программы.
Первое исполнение:
n=2<ENTER>
k=8<ENTER>
2 |
4 |
8 |
3 |
9 |
27 |
4 |
16 |
64 |
5 |
25 |
125 |
6 |
36 |
216 |
7 |
49 |
343 |
8 |
64 |
512 |
Второе исполнение:
n=-4<ENTER> k=-10<ENTER>
-4 |
16 |
-64 |
-5 |
25 |
-125 |
-6 |
36 |
-216 |
-7 |
49 |
-343 |
-8 |
64 |
-512 |
-9 |
81 |
-729 |
-10 |
100 |
-1000 |
Третье исполнение:
n=6<ENTER>
k=1<ENTER>
6 |
36 |
216 |
5 |
25 |
125 |
4 |
16 |
64 |
3 |
9 |
27 |
2 |
4 |
8 |
1 |
1 |
1 |
147
В программе использован параметрический цикл, параметр которого по-разному изменяется в зависимости от соотношения введенных значений переменных n и k. Если n≤ k, то приращение параметра +1. В противном случае –1. Условие прекращения цикла также зависит от значений n и k. Если n≤ k, то цикл следует продолжать, пока истинно условие i≤ k. В противном случае условием продолжения цикла служит истинность отношения i≥ k. Перечисленные правила воспроизведены в заголовке цикла с помощью условных выражений.
При программировании циклов нужно очень тщательно анализировать условия выхода из цикла, так как зацикливание – бесконечное выполнение операторов цикла – наиболее опасная и распространенная ошибка циклических алгоритмов.
ЗАДАНИЕ. В заголовке цикла предыдущей программы измените следующим образом проверку продолжения итераций:
n<k ? i<=k : i>=k
Результаты выполнения программы, приведенные выше, не изменятся. Однако попытка выполнить программу при условии, когда n==k, приведет к зацикливанию.
ЭКСПЕРИМЕНТ. Выполните указанное в предыдущем задании изменение в программе, проверьте ее работоспособность при n не равном k, затем введите, например, n=3 и k=3.
Чтобы прервать исполнение программы, придется использовать сочетание двух клавиш: Ctrl+C.
ЗАДАНИЕ. Напишите программу для решения той же задачи с применением:
1) оператора цикла с предусловием (while);
2) оператора цикла с постусловием (do….while).
Программа 05_10.с является изящной иллюстрацией возможностей выразительных средств языка Си, однако мало соответствует принципам структурного программирования. Именно поэтому текст программы 05_10.с достаточно труден для понимания при чтении.
148
ЗАДАНИЕ. Сконструируйте другую программу для решения той же задачи на основе принципов поэтапной детализации алгоритма (нисходящее проектирование).
Задача очень проста, поэтому ее решение с учетом правил структурного программирования может быть записано непосредственно (без промежуточных этапов детализации) в виде следующей последовательности шагов:
Ввести значение n Ввести значение k Если n<=k
Цикл от n до k с шагом 1 Печать i, i2, i3
Конец-цикла Иначе
Цикл от n до k с шагом –1 Печать i, i2, i3
Конец-цикла Все-если
Приведенный псевдокод можно непосредственно перевести в операторы языка Си:
/* 05_10_1.c - числа, их квадраты и кубы */ #include <stdio.h>
#define READI(VARIABLE) \
{ printf(#VARIABLE"="); scanf("%d",&VARIABLE); } int main ()
{
int i, n, k; READI(n); READI(k); if(n<=k)
for (i=n; i<=k; i++) printf("\n%d\t%d\t%d",i,i*i,i*i*i);
else
for (i=n; i>=k; i--) printf("\n%d\t%d\t%d",i,i*i,i*i*i);
return 0;
}
149
Результаты выполнения программы при тех же исходных данных полностью совпадают с результатами программы 05_10.с:
Циклы являются незаменимым инструментом программирования алгоритмов приближенных вычислений.
ЗАДАЧА 05-11. Определите "машинный нуль" относительно вводимого с клавиатуры вещественного числа. При вводе вещественного числа выполните проверку его положительности. При нарушении этого условия напечатайте предупреждающее сообщение и повторите ввод.
В следующей программе задача решена для чисел, представляемых в программе переменными типа double.
/* 05_11.c - машинный ноль для числа типа double */ #include <stdio.h>
int main ()
{
double real, estimate, zero; do { printf("\nreal=");
scanf("%le",&real);
if (real > 0.0) break; printf("real<=0 !!!");
}
while(1);
for (zero=real,estimate=real; estimate=real+zero, estimate != real; zero/=2) printf("\nestimate=%e\tzero=%e",
estimate,zero);
return 0;
}
Результат выполнения программы:
real=-16<ENTER> real<=0 !!!
real=0<ENTER> real<=0 !!!
150