[Язык C] Управляющие операторы С: ветвление и переходы (глава 7)

Седьмая глава в книжке Стивена Прата “C Primer Plus”. Начать хочу с годной программы divisors.c

Для заданного целого числа нужно вывести все целые числа, на которые заданное число делится без остатка; если таких делителей нет, необходимо вывести сообщение о том, что число является простым.

Простое число (prime) имеет ровно два различных делителя: единицу и самого себя;
Если делителей больше - это составное число (composite).

Первый вариант программы ищем простые числа в лоб, перебором делителей:

 #include <stdio.h>

 int main(void)
 {

 int x;
 int n;
 int prime = 1;

 printf("Enter a number\n");

 while (scanf ("%d", &x) == 1)
        {
        for (n=2, prime=1; n <= x; n++)
                {
                 if (x % n == 0)
                        {
                        printf("%d divided by %d\n", x, n);
                        prime = 0;
                        }
                }
        if (prime == 1)
                 printf("%d is a prime number\n", x);

        printf("Enter another number or 'q' to quit\n");
        }


 return 0;
 }

Давайте теперь ее улучшим: зная, что простые числа можно вычислить дойдя перебором до квадратного корня из n, оптимизируем сердце программы. Чтобы было лучше виден перебор значений, выведем процесс нахождения простых чисел (это замедлит перебор, зато поможет нам разобраться):

#include <stdio.h>

 int main(void)
 {

 int x;
 int n;
 int prime = 1;

 printf("Enter a number\n");

 while (scanf ("%d", &x) == 1)
        {
        for (n=2, prime=1; n*n <= x; n++)
                {
                printf("Trying %d*%d=%d\n", n, n, n*n);
                 if (x % n == 0)
                        {
                        printf("Ding! %d divided by %d and %d\n",
                                x, n, x/n);
                        prime = 0;
                        }
                }
        if (prime == 1)
                 printf("Nope. %d is a prime number\n", x);

        printf("Enter another number or 'q' to quit\n");
        }

 return 0;
 }

Вывод:

Enter a number
144
Trying 2*2=4
Ding! 144 divided by 2 and 72
Trying 3*3=9
Ding! 144 divided by 3 and 48
Trying 4*4=16
Ding! 144 divided by 4 and 36
Trying 5*5=25
Trying 6*6=36
Ding! 144 divided by 6 and 24
Trying 7*7=49
Trying 8*8=64
Ding! 144 divided by 8 and 18
Trying 9*9=81
Ding! 144 divided by 9 and 16
Trying 10*10=100
Trying 11*11=121
Trying 12*12=144
Ding! 144 divided by 12 and 12
Enter another number or 'q' to quit
15
Trying 2*2=4
Trying 3*3=9
Ding! 15 divided by 3 and 5
Enter another number or 'q' to quit

Ура! Теперь стало ясно что такое простые числа и как их искать 🙂 

Ну и последний штрих – сделаем так, чтобы строка из предыдущего вывода “Ding! 144 divided by 12 and 12”, не дублировала квадрат искомого числа. Для этого добавим развилку в оператор:

                 if (x % n == 0)
                        {
                        if ( n * n != x)
                           printf("Ding! %d divided by %d and %d\n",
                           x, n, x/n);
                        else
                                printf("Ding! %d divided by %d\n",
                                x, n);
                        prime = 0;
                        }

Вот и все! 🙂 Да здравствуют простые числа!

Далее.. Следующая программа, которая вызвала у меня некоторые трудности в ее составлении на вид элементарна. Посчитать количество слов, что может быть проще? Но не тут-то было. В этой программе я долго курил, как работать с флагами. Сначала я сделал программу, без флагов, но она по сути считала пробелы, а не слова.. Вот правильный вариант:

#include <stdio.h>
#include <ctype.h>

 int main(void)
 {

 int symbol = 0;
 int line = 0;
 int word = 0;
 char ch;
 int flag = 0;

 printf("Enter text for analysis (or | to exit)\n");

 while ((ch = getchar()) != '|')
        {
        symbol++;
        if (ch == '\n')
                line++;
        if (!isspace(ch) && flag==0) // not space and no flag
                {
                word++;              // count word
                flag=1;              // assign flag (checked!)
                }
        if (isspace(ch) && flag==1) // if space and got flag
                flag=0;             // remove flag

        }
 printf("Symbols: %d; Lines: %d; words: %d\n", symbol, line, word);


 return 0;
 }
Enter text for analysis (or | to exit)
Beliy sneg
Seriy led
192.168.0.1
|
Symbols: 33; Lines: 3; words: 5

Внизу не ставил гетчары, т.к. запускал ее в консоли. 

Понял суть флагов в этой программе – это эдакая “галочка”, чекпоинт – типа “пройдено” или “сделано”. Я как-то до этого воспринимал флаги наоборот. Наверное не важно как их воспринимать, в принципе… Но с моим первоначальным подходом программу надо было стартовать уже флагнутую в 1; что не есть хорошо с точки зрения логики. Учимся думать по новому 🙂

Теперь программа для малярных работ, хехе.

Сколько банок краски необходимо для того, чтобы покрасить заданное количество квадратных футов поверхности. Основной алгоритм прост: нужно разделить общее число квадратных футов на количество квадратных футов, которые можно покрасить содержимым одной банки. Тем не менее, предположим, что ответом будет 1,7 банки. В магазине можно купить только полные, а не частично заполненные банки, поэтому придется приобрести две банки…

#include <stdio.h>

 int main(void)
 {

 int can;
 int area;
 int rate = 15; // one can used for 15m2 of wall

 printf("Enter how much meters do you need to paint\n");

 while (scanf ("%d", &area) == 1) // enter m2
        {
        can = area / rate;
        // how much cans do we need to paint it

        can += ((area % rate == 0 )) ? 0 : 1;
        // we can't leave part of wall unpainted

        printf("To paint %d m2 you need %d %s\n",
                area, can,can == 1 ? "can" : "cans");
        printf("Enter another area value (or 'q' to quit)\n");
        }

 getchar(); getchar();
 return 0;
 }
Enter how much meters do you need to paint
121
To paint 121 m2 you need 9 cans
Enter another area value (or 'q' to quit)
994
To paint 994 m2 you need 67 cans
Enter another area value (or 'q' to quit)
4
To paint 4 m2 you need 1 can
Enter another area value (or 'q' to quit)

Покрасили!

Теперь программа подсчета очков, которая кроме того толково ищет минимальное и максимальное значение.

#include <stdio.h>
#define MIN 0.0f
#define MAX 100.0f

 int main(void)
 {

 float score;
 float total = 0.0f;
 int n = 0;
 float min = MAX;
 float max = MIN;

 printf("Enter results:\n");

 while (scanf("%f", &score) == 1)
 {
        if (score < MIN || score > MAX)
        {
                printf("%0.1f - wrong value\n", score);
                continue;
        }
 printf("Getting %0.1f\n", score);
 min = (score < min)? score: min; 
 max = (score > max)? score: max; 
 total +=score;
 n++;
 }
 if (n>0)
 {      printf("Average value for %d results is %0.1f\n",
                n, total/n);
        printf("Low = %0.1f, high = %0.1f\n", min, max);
 }
 else
        printf("Correct results weren't entered\n");


 getchar(); getchar();  getchar(); 
 return 0;
 }
Enter results:
32
Getting 32.0
96
Getting 96.0
11
Getting 11.0
123
123.0 - wrong value
491
491.0 - wrong value
1
Getting 1.0
Average value for 4 results is 35.0
Low = 1.0, high = 96.0

Тут сложный момент – это начальные условия (а не собственно оператор ‘continue’, которому посвящена эта программа). Условия такие:

float min = MAX;
float max = MIN;

Когда такое вижу, у меня случается гуманитарный когнитивный диссонанс. На деле же это нужно для того, чтобы найти минимальные и максимальные значения – чтобы первое сравнение min’имума сравнивалось с максимальным значением (вдруг вы введете 99), и оно точно “попало”. Тоже самое относится и к max.

Следующая программа читает букву и отвечает выводом названия животного,
которое начинается с такой буквы:

#include <stdio.h>
#include <ctype.h>

int main(void)
{

 char ch;

 printf("Please enter lowercase letter (a-e):\n");

 while ((ch = getchar()) != '#')
 {
    if (islower(ch))
        switch (ch)
        {
            case 'a' :
                printf("antelope, wild african deer\n");
                break;
            case 'b' :
                printf("beaver, big water rodent\n");
                break;
            case 'c' :
                printf("cat, got pawns, tail and whiskers\n");
                break;
            case 'd' :
                printf("dog, domesticated wolf\n");
                break;
            case 'e' :
                printf("elephant, biggest land mammal\n");
                break;
            default :
                printf("Donno such animal yet..\n");
        }
    else
        printf("I know only lowercase letters\n");
 while (getchar() != '\n')
    continue;
 printf("Please enter another letter or # to quit\n");
 }
 printf("Bye!");


getchar(); getchar();
return 0;
}
Please enter lowercase letter (a-e):
a
antelope, wild african deer
Please enter another letter or # to quit
b
beaver, big water rodent
Please enter another letter or # to quit
q
Donno such animal yet..
Please enter another letter or # to quit
B
I know only lowercase letters
Please enter another letter or # to quit
d
dog, domesticated wolf
Please enter another letter or # to quit
#
Bye!

В этой программе помимо switch, case и while (getchar() != '\n') continue; интересной является функция (islower(ch)). Изначально, когда я писал эту программу, я использовал (islower(ch))==1 и это не работало. При помощи вывода printf я понял, что (islower(ch)) выдает 2 если введена строчная буква и 0 если заглавная; т.е. истина в этой функции не есть 1 (ну а 2 – тоже истина при проверке функции). Любопытно 🙂

[catlist]

This entry was posted in С (Си). Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *