Урок №5 Цикл for и подсчёт количества

Теория:

IБезопасное считывание

На прошлых уроках мы прошли способ считывания данных при помощи функции scanf(). Но считывание – процесс непредсказуемый, пользователь может не ввести то, что необходимо для корректной работы программы, или даже попытаться взломать программу путём ввода всяких вредоносных данных.

Чтобы сделать считывание безопасным, необходимо осуществить проверку, что пользователь ввёл именно то, что требуется. Для этого в языке С/С++ у функции scanf() была введена опция возврата корректно считанных аргументов.

Функция scanf() возвращает количество корректно считанных аргументов.

Это означает, что при попытке считать, например 3 числа, в случае корректного считывания именно трёх чисел указанного типа, функция scanf() вернёт число 3.

Почти все функции в языке С/С++ что-то возвращают. Например уже известная нам функция main() возвращает целые числа, так как мы пишем return 0; в конце тела данной функции.

Для того, чтобы проверить, вернула ли функция scanf() то количество аргументов, которое она попыталась считать нужно воспользоваться циклом if, который мы прошли на прошлом уроке:

if (scanf("%d%d", &x, &y) == 2){} // проверяем, что функция scanf() вернула число 2 при считывании двух целых чисел в две переменные типа int: x и y

Но нам необходимо принимать меры не в случае, когда считывание произошло корректно, а наоборот: при некорректном считывании. Поэтому безопасное считывания в языке С/С++ выглядит следующими образом:

if (scanf("%d%d", &x, &y) != 2){ // безопасное считывание
    printf("Reading error.\n"); // уведомляем пользователя об ошибке чтения в случае некорректного считывания
    return 1; // возвращаем -1, если не установлен другой код ошибки чтения
}
В крупных компаниях при разработке чего-либо всегда существует перечень ошибок и их кодов. Это необходимо для быстрой идентификации ошибки по её коду, а также по поиску фрагмента кода, в котором произошла данная ошибка.

IIЦикл for

Ещё одним очень распространённым циклом является цикл  for.

Определение

Цикл for осуществляет многократный и индексированный повтор команд своего тела. Проще говоря, цикл for создаёт или берёт уже созданный индекс, присваивает ему стартовое значение, проверяет, что оно удовлетворяет финишному условию, затем осуществляет выполнение команд своего тела. После того, как команды были выполнены, индекс изменяется в соответствии с шаговой процедурой, после чего снова происходит проверка финишного условия, и если оно выполнено, то снова выполняются команды тела, а если финишное условие не выполнено, цикл for завершает свою работу.

Работа цикла for

Давайте разберёмся более подробно, как устроена работа цикла for. Как можно понять из определения, для корректной работы данного цикла необходимо:

  • Стартовое значение
  • Финишное условие
  • Шаговая процедура

Рассмотрим каждый пункт подробнее.

Стартовое значение – это то значение, которое примет индекс в самом начале работы цикла  for.

Финишное ограничение – это условие, выполнение которого способствует очередному выполнению команд  из тела цикла for, а невыполнение – завершению цикла for.

Шаговая процедура – это процесс изменения индекса после очередного выполнения команд из тела цикла for.

Синтаксис цикла for

Теперь давайте разберёмся, как устроен синтаксис цикла for. На самом деле всё очень просто. Необходимо лишь указать через точку с запятой ; все необходимые элементы:

for (int i = 0; i < 5; i++){} // создаём цикл for с индексом от 0 до 5 и шагом 1

Разберём синтаксис детально:

int i = 0 – процесс создания индекса и присваивание ему стартового значения. В роли индекса выступает переменная i типа int, а стартовым значением является число 0.

i < 5 – финишное ограничение. Если индекс i строго меньше числа 5, цикл for продолжает свою работу, иначе – завершает.

i++ – шаговая процедура. Как только цикл for  выполнил все команды своего тела, индекс i становится больше на единицу.

Операция i++ эквивалентна операциям i += 1 или i = i + 1, что означает увеличение переменной i на единицу
Если индекс i создаётся в первом аргументе цикла for, то он существует только внутри цикла . Попытка обратиться к переменной int i вне цикла приведёт к ошибке.

Как уже было замечено, индекс для цикла for может быть уже созданным. В таком случае синтаксис цикла for выглядит следующим образом:

int i = 0; // создаём переменную
for (i = 10; i >= 3; i -= 2){} // создаём цикл for с индексом от 10 до 3 включительно и шагом -2
Обратите внимание, что стартовое значение в цикле for всё равно необходимо задавать.
Финишное ограничение в цикле for может быть практически любого типа. Главное, чтобы оно включало в себя ограниченное количество значений индекса.
Шаговая процедура в цикле for также может быть произвольной. Необходимо только позаботиться о том, чтобы количество проходов в цикле for было ограниченным.
Примеры работы цикла for

Рассмотрим процесс работы цикла for на конкретных примерах.

for (int i = 0; i < 5; i++){ // создаём цикл for с индексом от 0 до 10 и шагом 1
    printf("i = %d\n"); // выписываем значение индекса i на экран
}

После выполнения данного кода на экран будет выведено:

i = 0
i = 1
i = 2
i = 3
i = 4
Обратите внимание, что индекс i пробегает 5 значений от 0 до 4 включительно. Значение 5 индекс i не принимает, так как условие 5 < 5 в финишном ограничении ложно.

IIIПодсчёт количества

Давайте рассмотрим применения цикла for в алгоритмах. При помощи данного цикла можно осуществить подсчёт количества.

Допустим, необходимо посчитать, сколько чисел от 1 до 100 включительно кратны 3. Конечно, можно просто поделить 100 на 3 и взять целую часть, поэтому использовать программирование для этой задачи не совсем рационально. Однако существует множество задач, решить которые вручную практически невозможно, а при помощи цикла for это можно сделать за пару минут.

Но для начала рассмотрим простой пример. Итак, для того, чтобы посчитать, сколько чисел от 1 до 100 включительно кратны 3, необходимо запустить цикл for от 1 до 100 включительно с единичным шагом.

for (int i = 1; i <= 100; i++){} // создаём цикл for с индексом от 1 до 100 включительно и шагом 1

Такой цикл осуществит перебор чисел от 1 до 100 включительно, но как нам отобрать среди них те, которые кратны трём?

Для этого нам поможет цикл if и оператор взятия остатка %:

for (int i = 1; i <= 100; i++){ // создаём цикл for с индексом от 1 до 100 включительно и шагом 1
    if (i % 3 == 0){} // проверяем, что число i кратно трём
}

Но как быть дальше? Мы можем, конечно, вывести на экран все числа от 1 до 100 включительно, которые кратны трём:

for (int i = 1; i <= 100; i++){ // создаём цикл for с индексом от 1 до 100 включительно и шагом 1
    if (i % 3 == 0){ // проверяем, что число i кратно трём
        printf("%d\n", i); // выводим число, кратное трём на экран
    }
}

Но ведь нам необходимо посчитать количество таких чисел, а не вывести на экран. Не будем же мы после вывода этих чисел на экран вручную считать их количество. Так как же нам быть?

Давайте думать логически. Чтобы посчитать количество чего-либо, а затем вывести его, необходимо где-то хранить число, являющееся нужным количеством, а где в языке С/С++ хранятся числа? Всё верно, в переменных. В таком случае давайте создадим специальную переменную-счётчик, которая и будет хранить в себе количество.

А как осуществить непосредственно подсчёт? Мы перебираем все числа, проверяем их на кратность трём, в случае кратности их трём выписываем их на экран. А должны в этом случае осуществлять подсчёт, то есть увеличивать количество таких чисел на единицу. Но ведь в этом нет ничего сложного. Давайте же сделаем это:

int count = 0; // создаём переменную-счётчик
for (int i = 1; i <= 100; i++){ // создаём цикл for с индексом от 1 до 100 включительно и шагом 1
    if (i % 3 == 0){ // проверяем, что число i кратно трём
        count++; // увеличиваем счётчик на единицу, если нашли необходимое число
    }
}

В коде выше мы создали переменную count типа int, положили в неё число 0, так как в начале мы ещё не обнаружили ни одного числа, кратного трём. Затем мы осуществили перебор всех чисел от 1 до 100 включительно при помощи цикла for. Каждое число мы проверили на кратность трём с помощью цикла if и оператора взятия остатка %, помня, что число кратно трём тогда и только тогда, когда его остаток при делении на 3 равен нулю. В случае, если число кратно трём, мы увеличиваем переменную count на единицу с помощью операции count++;. Таким образом после завершения цикла for переменная count будет содержать в себе необходимое количество.

Но данную задачу можно было решить без использования цикла if и оператора взятия остатка %. Очевидно, что трём кратно каждое третье число. Поэтому можно запустить цикл for от трёх (так как самое первое число после единицы, кратное трём – это три) до 100 с шагом 3. Такой цикл for сразу осуществит перебор всех чисел т 1 до 100 включительно, которые кратны трём, поэтому в его теле можно просто увеличивать переменную count на единицу:

int count = 0; // создаём переменную-счётчик
for (int i = 3; i <= 100; i += 3){ // создаём цикл for с индексом от 3 до 100 включительно и шагом 3
    count++; // увеличиваем счётчик на единицу, если нашли необходимое число
}

Данный способ будет работать более чем в 3 раза быстрее, так как вместо 100 проходов, цикл for выполнит только 33, при этом не будет 100 операций вычисления остатка при делении на 3 и 100 циклов if.

Практика

1Задача №1.

Выписать на экран все числа от 12 до 43 включительно, которые кратны 5.

Решение:
#include <stdio.h> // подключаем библиотеку stdio.h
#include <stdlib.h> // подключаем библиотеку stdlib.h

int main() { //создаём главную функцию
    for (int i = 15; i < 43; i += 5){ // запускаем цикл for с индексом от 15 до 43 и шагом 5
        printf("%d ", i); // выписываем значение индекса i
    }
    return 0; // завершаем с кодом 0 - успех
}
Пример работы программы:
15 20 25 30 35 40
Process returned 0 (0x0)   execution time : 0.009 s
Press any key to continue.

2Задача №2.

Выписать на экран все числа от 12000 до 25000 включительно, которые кратны и 11 и 12 и 13 одновременно.

Решение:
#include <stdio.h> // подключаем библиотеку stdio.h
#include <stdlib.h> // подключаем библиотеку stdlib.h

int main() { //создаём главную функцию
    for (int i = 12012; i < 25000; i += 1716){ // запускаем цикл for с индексом от 12012 до 250000 и шагом 1716
        printf("%d ", i); // выписываем значение индекса i
    }
    return 0; // завершаем с кодом 0 - успех
}
Заметим, что кратность и 11 и 12 и 13 равносильна кратности произведению этих чисел, то есть кратности на число 1716 — это и есть шаг цикла for.
Стартовое значение для цикла for – наименьшее число, кратное 1716, но большее 12000 — это 12012. Его можно вычислить на калькуляторе.
Пример работы программы:
12012 13728 15444 17160 18876 20592 22308 24024
Process returned 0 (0x0)   execution time : 0.005 s
Press any key to continue.
Альтернативное решение:

Данную задачу можно было решить чуть более медленным способом, но зато без дополнительных подсчётов на калькуляторе. Очевидно, что число 12000 кратно 12, и каждое двенадцатое число после него тоже, поэтому можно запустить цикл for от 12000 с шагом 12 и проверять числа на кратность 11 и 13:

#include <stdio.h> // подключаем библиотеку stdio.h
#include <stdlib.h> // подключаем библиотеку stdlib.h

int main() { //создаём главную функцию
    for (int i = 12000; i < 25000; i += 12){ // запускаем цикл for с индексом от 12000 до 250000 и шагом 12
        if (i % 11 == 0 && i % 13 == 0){ // проверяем кратность 11 и 13
            printf("%d ", i); // выписываем значение индекса i
        }
    }
    return 0; // завершаем с кодом 0 - успех
}
Пример работы программы:
12012 13728 15444 17160 18876 20592 22308 24024
Process returned 0 (0x0)   execution time : 0.007 s
Press any key to continue.

3Задача №3.

Выписать на экран все числа от -500 до 500 включительно, которые оканчиваются на 7 и при этом кратны 7.

Решение:
#include <stdio.h> // подключаем библиотеку stdio.h
#include <stdlib.h> // подключаем библиотеку stdlib.h
#include <math.h> // подключаем библиотеку math.h

int main() { //создаём главную функцию
    for (int i = -500; i <= 500; i++){ // запускаем цикл for с индексом от -500 до 500 и шагом 1
       if (abs(i) % 10 == 7 && i % 7 == 0){ // проверяем, что i оканчивается на 7 и кратно 7
           printf("%d ", i); // выписываем значение индекса i
       }
    } // закрываем цикл for
    return 0; // завершаем с кодом 0 - успех
}
Пример работы программы:
-497 -427 -357 -287 -217 -147 -77 -7 7 77 147 217 287 357 427 497
Process returned 0 (0x0)   execution time : 0.008 s
Press any key to continue.

4Задача №4.

Выписать на экран все числа от -100 до 100 включительно, последняя цифра которых чётна, и при этом само число кратно 3 или 7, но не кратно 5.

Решение:
#include <stdio.h> // подключаем библиотеку stdio.h
#include <stdlib.h> // подключаем библиотеку stdlib.h
#include <math.h> // подключаем библиотеку math.h

int main() { //создаём главную функцию
    for (int i = -100; i <= 100; i++){ // запускаем цикл for с индексом от -100 до 100 и шагом 1
       if ((abs(i) % 10) % 2 == 0 && (i % 3 == 0 || i % 7 == 0) && i % 5 != 0){ // проверяем, что последняя цифра i чётна, и при этом i кратно 3 или 7, но не кратно 5
           printf("%d ", i); // выписываем значение индекса i
       }
    } // закрываем цикл for
    return 0; // завершаем с кодом 0 - успех
}
Пример работы программы:
-98 -96 -84 -78 -72 -66 -56 -54 -48 -42 -36 -28 -24 -18 -14 -12 -6 6 12 14 18 24 28 36 42 48 54 56 66 72 78 84 96 98
Process returned 0 (0x0)   execution time : 0.009 s
Press any key to continue.

Домашнее задание:

1Задача №1.

Выписать на экран все числа от 1 до 1000 включительно, которые кратны 2 и 3, но не кратны 4 и 9.

Решение:
#include <stdio.h> // подключаем библиотеку stdio.h
#include <stdlib.h> // подключаем библиотеку stdlib.h

int main() { //создаём главную функцию
    for (int i = 1; i <= 1000; i++){ // запускаем цикл for с индексом от 1 до 1000 и шагом 1
       if (i % 2 == 0 && i % 3 == 0 && i % 4 != 0 && i % 9 != 0){ // проверяем, что последняя цифра i кратно 2 и 3, но не кратно 4 и 9.
           printf("%d ", i); // выписываем значение индекса i
       }
    } // закрываем цикл for
    return 0; // завершаем с кодом 0 - успех
}
Пример работы программы:
6 30 42 66 78 102 114 138 150 174 186 210 222 246 258 282 294 318 330 354 366 390 402 426 438 462 474 498 510 534 546 570 582 606 618 642 654 678 690 714 726 750 762 786 798 822 834 858 870 894 906 930 942 966 978
Process returned 0 (0x0)   execution time : 0.010 s
Press any key to continue.

2Задача №2.

Выписать на экран все чётные числа от -1111 до 1111 включительно, которые кратны 11 или 21, и при этом оканчиваются на 4 или на 6.

Решение:
#include <stdio.h> // подключаем библиотеку stdio.h
#include <stdlib.h> // подключаем библиотеку stdlib.h
#include <math.h> // подключаем библиотеку math.h

int main() { //создаём главную функцию
    for (int i = -1111; i <= 1111; i++){ // запускаем цикл for с индексом от -1111 до 1111 и шагом 1
       if ((abs(i) % 11 == 0 || abs(i) % 21 == 0) && (abs(i) % 10 == 4 || abs(i) % 10 == 6)){ // проверяем, что i кратно 11 или 21, и при этом оканчивается на 4 или на 6
           printf("%d ", i); // выписываем значение индекса i
       }
    } // закрываем цикл for
    return 0; // завершаем с кодом 0 - успех
}
Пример работы программы:
-1056 -1034 -966 -946 -924 -836 -814 -756 -726 -714 -704 -616 -594 -546 -506 -504 -484 -396 -374 -336 -294 -286 -264 -176 -154 -126 -84 -66 -44 44 66 84 126 154 176 264 286 294 336 374 396 484 504 506 546 594 616 704 714 726 756 814 836 924 946 966 1034 1056
Process returned 0 (0x0)   execution time : 0.007 s
Press any key to continue.

3Задача №3.

Найти сколько среди всех нечётных чисел от 10 до 100000 включительно таких, что они оканчиваются на 7 или на 9, не делятся ни на 7 ни на 9, но при этом кратны 79 и 97.

Решение:
#include <stdio.h> // подключаем библиотеку stdio.h
#include <stdlib.h> // подключаем библиотеку stdlib.h

int main() { //создаём главную функцию
    int count = 0; // создаём переменную-счётчик
    for (int i = 11; i <= 100000; i += 2){ // запускаем цикл for с индексом от 11 до 100000 и шагом 2
       if ((i % 10 == 7 || i % 10 == 9) && i % 7 != 0 && i % 9 != 0 && i % 79 == 0 && i % 97 == 0){ // проверяем, что i удовлетворяет необходимым условиям
           count++; // увеличиваем счётчик на единицу, если нашли необходимое число
       }
    }
    printf("%d\n", count); // выписываем ответ
    return 0; // завершаем с кодом 0 - успех
}
Пример работы программы:
2

Process returned 0 (0x0)   execution time : 0.007 s
Press any key to continue.

4Задача №4.

Определить, каких чисел среди всех чисел от 1 до 1000000 включительно больше:

  • оканчивающихся на 2 или на 9 и при этом кратных 2 или 9
  • оканчивающихся на 3 или на 8 и при этом кратных 3 или 8
Решение:
#include <stdio.h> // подключаем библиотеку stdio.h
#include <stdlib.h> // подключаем библиотеку stdlib.h

int main() { //создаём главную функцию
    int count_29 = 0, count_38 = 0; // создаём переменные-счётчики
    for (int i = 1; i <= 1000000; i++){ // запускаем цикл for с индексом от 1 до 1000000 и шагом 1
       if ((i % 10 == 2 || i % 10 == 9) && (i % 2 == 0 || i % 9 == 0)){ // проверяем, что i удовлетворяет необходимым условиям
           count_29++; // увеличиваем соответствующий счётчик на единицу
       }
       if ((i % 10 == 3 || i % 10 == 8) && (i % 3 == 0 || i % 8 == 0)){ // проверяем, что i удовлетворяет необходимым условиям
           count_38++; // увеличиваем соответствующий счётчик на единицу
       }
    }
    if (count_29 > count_38){ // проверяем, каких чисел больше
        printf("There are more numbers that end in 2 or 9 and are multiples of 2 or 9 (%d > %d)\n", count_29, count_38); // выписываем ответ
    } else if (count_38 > count_29){
        printf("There are more numbers that end in 3 or 8 and are multiples of 3 or 8 (%d > %d)\n", count_38, count_29); // выписываем ответ
    } else { // если не выполнено ни то ни другое условие, то количества одинаковые
        printf("There are the same count of such numbers (%d = %d)\n", count_38, count_29);
    }
    return 0; // завершаем с кодом 0 - успех
}
Пример работы программы:
There are more numbers that end in 2 or 9 and are multiples of 2 or 9 (111112 > 83334)

Process returned 0 (0x0)   execution time : 0.011 s
Press any key to continue.

5Задача №5.

Определить, каких чисел от 1 до 1000000 больше и на сколько: тех, среди двух последних цифр которых есть 2 или тех, среди двух последних цифр которых её нет.

Чтобы получить предпоследнюю цифру числа, необходимо разделить его на 10 в целых числах (для типа int просто разделить на 10 i / 10), а затем также взять остаток при делении на 10 i % 10.
Решение:
#include <stdio.h> // подключаем библиотеку stdio.h
#include <stdlib.h> // подключаем библиотеку stdlib.h

int main() { //создаём главную функцию
    int count_with_2 = 0, count_without_2 = 0; // создаём переменные-счётчики
    for (int i = 1; i <= 1000000; i++){ // запускаем цикл for с индексом от 1 до 1000000 и шагом 1
        if (i % 10 == 2 || (i / 10) % 10 == 2){ // проверяем, что i удовлетворяет необходимым условиям
           count_with_2++; // увеличиваем соответствующий счётчик на единицу
        } else {
            count_without_2++; // увеличиваем соответствующий счётчик на единицу
        }
    }
    if (count_with_2 > count_without_2){ // проверяем, каких чисел больше
        printf("Numbers with the number 2 among the last two digits are more than %d = %d - %d\n", count_with_2 - count_without_2, count_with_2, count_without_2); // выписываем ответ
    } else if (count_without_2 > count_with_2){
        printf("Numbers without the number 2 among the last two digits are more than %d = %d - %d\n", count_without_2 - count_with_2, count_without_2, count_with_2); // выписываем ответ
    } else { // если не выполнено ни то ни другое условие, то количества одинаковые
        printf("There are the same count of such numbers (%d)\n", count_with_2);
    }
    return 0; // завершаем с кодом 0 - успех
}
Пример работы программы:
Numbers without the number 2 among the last two digits are more than 620000 = 810000 - 190000

Process returned 0 (0x0)   execution time : 0.010 s
Press any key to continue.

6Задача №6.

Трёхзначное число симметрично, если оно пишется одинаково и слева направо и справа налево. Определить, какой процент трёхзначных чисел являются симметричными.

Чтобы получить первую цифру трёхзначного числа, необходимо разделить его на 100 в целых числах.
Чтобы вывести на экран символ процента, необходимо в маске функции printf написать %%. Тогда компилятор поймёт, что это не оператор короткого имени типа переменной, а просто символ процента.
При вычислении доли необходимо сконвертировать целочисленные количества в тип double. Для этого достаточно просто взять переменную, которую необходимо сконвертировать в круглые скобки и написать перед ними double.
Решение:
#include <stdio.h> // подключаем библиотеку stdio.h
#include <stdlib.h> // подключаем библиотеку stdlib.h

int main(){ // создаём главную функцию
    int count = 0; // создаём переменную-счётчик
    for (int i = 100; i < 1000; i++){ // запускаем цикл for с индексом от 100 до 1000 и шагом 1
        if (i % 10 == i / 100){ // проверяем, что первая цифра равна последней
            count++; // увеличиваем счётчик на единицу
        }
    }
    printf("%.2lf%%\n", (double(count) / 9.0)); // выписываем ответ
    return 0; // возвращаем 0 - успех
}
Пример работы программы:
10.00%

Process returned 0 (0x0)   execution time : 0.005 s
Press any key to continue.
Всего трёхзначных чисел 900 штук. При вычислении процентного соотношения, необходимо долю умножить на 100. Чтобы не выполнять лишних действий, было сразу поделено на 9.

7Задача №7.

Трёхзначное число монотонное, если все три его цифры расположены в порядке убывания или возрастания. Определить, какой процент трёхзначных чисел являются монотонными.

Решение:
#include <stdio.h> // подключаем библиотеку stdio.h
#include <stdlib.h> // подключаем библиотеку stdlib.h

int main(){ // создаём главную функцию
    int count = 0; // создаём переменную-счётчик
    int a1 = 0, a2 = 0, a3 = 0; // создаём целочисленные переменные
    for (int i = 100; i < 1000; i++){ // запускаем цикл for с индексом от 100 до 1000 и шагом 1
        a3 = i % 10; // вычисляем последнюю цифру числа
        a2 = (i / 10) % 10; // вычисляем вторую с конца цифру числа
        a1 = i / 100; // вычисляем первую цифру числа
        if ((a1 < a2 && a2 < a3) || (a1 > a2 && a2 > a3)){ // проверяем, что трёхзначное число монотонное
            count++; // увеличиваем счётчик на единицу
        }
    }
    printf("%.2lf%%\n", (double(count) / 9.0)); // выписываем ответ
    return 0; // возвращаем 0 - успех
}
Пример работы программы:
22.67%

Process returned 0 (0x0)   execution time : 0.005 s
Press any key to continue.

8Задача №8*.

Трёхзначное число особое, если какая-то из его цифр является суммой двух других, и при этом в числе нет ни одной цифры 3, но есть хотя бы одна цифра 8. Определить, какой процент трёхзначных чисел являются особыми.

Решение:

Для достижения наилучшего результата и доступа ко всему курсу необходимо приобрести курс еженедельных индивидуальных или групповых занятий с преподавателем в режиме онлайн. Наши преподаватели обучат Вас создавать уникальные алгоритмы и самостоятельно реализовывать их в программном коде с соблюдением стандартов оформления.

Для записи на бесплатный пробный урок просто заполните форму ниже: