Pull to refresh

Небольшая задача на C/C++ для разминки

Reading time3 min
Views41K
Предлагаю решить задачу. Как вариант, можно предложить решить ее соискателям при проведении собеседований (в дополнение). Задача очень просто решается, но создает паузу у людей, не встречавшихся с ней раньше или не попытавшихся проанализировать свойства операторов-циклов при изучении или после.


Используя только одну переменную типа unsigned char (8-битный по условию), ровно один оператор цикла и не используя условного оператора if и условной тернарной операции (?:), создать цикл ровно из 256 шагов, тело которого, даже если оно пусто, исполняется ровно 256 раз. В частном случае такой цикл может вывести все целые числа от 0 до 255 включительно.

Решение задачи


Скрытый текст
#include <iostream>

int main() {
    unsigned int i = 0;
    do {
        std::cout << i << " ";
    } while (++i);
    return 0;
}


Интересно, что совокупность приведенных в задаче условий требует применения цикла do и не позволяет обойтись операторами while или for. Именно применение последних двух циклов является основной ошибкой при решении данной задачи, приводящей в большинстве случаев к пропуску шага (выполнению 255 шагов вместо 256 требуемых в услови) или к созданию бесконечного цикла. На такую ошибку наталкивает то, что циклы for/while используются значительно чаще do, я где-то встречал субъективную оценку соотношения 95%:5%.

Цикл повторяет выполнение двух действий: проверку условия и исполнение тела. Способом чередования этих действий и различаются циклы с предусловием (while) и с постусловием (do). Между циклами много общего, в частности, используя условный оператор if и один из видов цикла всегда можно сформировать конструкцию, которая будет вести себя как вторая разновидность цикла (например, из while и if можно написать do). Отсюда и одно из требований задачи: не использовать условный оператор if. Тем не менее различие в порядке действий наделяет две разновидности циклов различием в свойствах. Во-первых, тело цикла с предусловием может не выполниться ни разу, в то время как тело цикла с постусловием выполняется всегда хотя бы один раз. Во-вторых, в циклах for/while проверка условия выполняется на 1 раз больше, чем тело цикла, а в do тело цикла выполняется столько же раз, сколько проверка условия или на 1 раз больше если тело принудительно прерывает цикл. Поэтому «ровно 256 шагов» в условии задачи является избыточным, а «тело которого,… исполняется ровно 256 раз» — нет. Вообще, формулировка «цикл из 256 шагов» — уязвима: если условие проверялось 256 раз, а тело выполнялось 255 раз, можно ли утвержать, что цикл состоит только из 255 шагов? Понятно, что проверка условия может быть операцией любой сложности и выполнять любые побочные действия. Ранее было сформулировано промежуточное ограничение: запрет на выполнение требуемых операций тела цикла (например, вывода) при проверке условия. Однако требование исполнения именно тела цикла ровно 256 раз является более строгим, конкретным и, в кончном итоге, корректным. На более абстрактном уровне преобразование условия в последовательность «действие, затем условие», где действие и условие связаны операциями последовательного вычисления (,), логическими операциями или иным способом, фактически делает проверку условия не началом итерации цикла с предусловием и превращает его в цикл с постусловием.

Наконец, идиомой цикла из N шагов в C/C++ является: for (int i = 0; i < N; i++). Свойством такой конструкции является то, что счетчик цикла i принимает (N+1) различных значений от 0 до N включительно. Следовательно, 8-битный тип, принимающий ровно 256 значений может использоваться только для создания подобных циклов не более чем из 255 шагов.
Tags:
Hubs:
Total votes 44: ↑12 and ↓32-20
Comments61

Articles