Теория:
IБезопасное считывание
На прошлых уроках мы прошли способ считывания данных при помощи функции scanf()
. Но считывание – процесс непредсказуемый, пользователь может не ввести то, что необходимо для корректной работы программы, или даже попытаться взломать программу путём ввода всяких вредоносных данных.
Чтобы сделать считывание безопасным, необходимо осуществить проверку, что пользователь ввёл именно то, что требуется. Для этого в языке С/С++ у функции scanf()
была введена опция возврата корректно считанных аргументов.
Это означает, что при попытке считать, например 3 числа, в случае корректного считывания именно трёх чисел указанного типа, функция scanf()
вернёт число 3
.
Для того, чтобы проверить, вернула ли функция 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
становится больше на единицу.
Как уже было замечено, индекс для цикла for
может быть уже созданным. В таком случае синтаксис цикла for
выглядит следующим образом:
int i = 0; // создаём переменную
for (i = 10; i >= 3; i -= 2){} // создаём цикл for с индексом от 10 до 3 включительно и шагом -2
Примеры работы цикла 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
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 - успех
}
Пример работы программы:
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.
2Задача №2.
Выписать на экран все чётные числа от -1111 до 1111 включительно, которые кратны 11 или 21, и при этом оканчиваются на 4 или на 6.
3Задача №3.
Найти сколько среди всех нечётных чисел от 10 до 100000 включительно таких, что они оканчиваются на 7 или на 9, не делятся ни на 7 ни на 9, но при этом кратны 79 и 97.
4Задача №4.
Определить, каких чисел среди всех чисел от 1 до 1000000 включительно больше:
- оканчивающихся на 2 или на 9 и при этом кратных 2 или 9
- оканчивающихся на 3 или на 8 и при этом кратных 3 или 8
5Задача №5.
Определить, каких чисел от 1 до 1000000 больше и на сколько: тех, среди двух последних цифр которых есть 2 или тех, среди двух последних цифр которых её нет.
6Задача №6.
Трёхзначное число симметрично, если оно пишется одинаково и слева направо и справа налево. Определить, какой процент трёхзначных чисел являются симметричными.
7Задача №7.
Трёхзначное число монотонное, если все три его цифры расположены в порядке убывания или возрастания. Определить, какой процент трёхзначных чисел являются монотонными.
8Задача №8*.
Трёхзначное число особое, если какая-то из его цифр является суммой двух других, и при этом в числе нет ни одной цифры 3, но есть хотя бы одна цифра 8. Определить, какой процент трёхзначных чисел являются особыми.