Циклические конструкции в языке Си
Основное преимущество компьютера перед человеком заключается в том, что он может очень быстро выполнять операции и хранить большие объёмы информации. При этом он не устаёт и не ошибается. Но данными преимуществами ещё нужно научиться грамотно пользоваться. Например, какая польза от того, что компьютер может выполнить миллион операций в секунду, если нам нужно предварительно записать каждую из этого миллиона операций? Сколько времени на это уйдёт? Очевидно, что нам требуется способ записывать много простых операций малыми усилиями, желательно в 2-3 строчки кода. И, конечно, такой способ есть – это циклические конструкции (циклы) .
Цикл – конструкция, которая позволяет указать компьютеру выполнить некоторую последовательность операций много раз.
В этом уроке мы обсудим, как устроены циклические конструкции в языке Си, и научимся ими пользоваться.
В языке Си используются три основных вида циклов:
-
цикл со счётчиком for while do-while
Сохрани в закладки или поддержи проект.
Что такое циклические конструкции
Циклические конструкции
Циклические конструкции применяют для повторения некоторого блока кода на основании условия цикла. В языке С используются циклические конструкции while , for и do — while .
Конструкция while
Цикл while имеет следующий синтаксис.
// Выполнение тела цикла, если выражение истинно
Другими словами, циклы while имеет смысл использовать в тех случаях, когда соответствующий оператор или блок операторов необходимо выполнять до тех пор, пока условное выражение истинно. Пример формирования строки, состоящей из нечетных цифр:
const char str [] = «0123456789»;
char OddNums [5]; //Строка для хранения нечетных цифр
с = 0; //Счетчик циклов
i = 0; //Индекс массива OddNums
//Если остаток от деления с на 2 = 1, то записываем в i — ю позицию массива OddNums с-й
//элемент строки str , после чего значение i автоматически инкрементируется
if (( с % 2) == 1) OddNums[i++] = str[c];
Конструкция for
Цикл for имеет следующий синтаксис.
for (выражение1; выражение2; выражение3)
// Выполнение тела цикла
Выражение 1 выполняется только один раз при входе в цикл, и обычно представляет собой оператор присваивания некоторого начального значения счетчику цикла. Выражение2 — это условное выражение, определяющее момент выхода из цикла (цикл выполняется до тех пор, пока оно равно TRUE или 1).
Выражение3 — еще один оператор присваивания, в котором обычно изменяется счетчик цикла или некоторая переменная, влияющая на выполнение условия в выражении2. Выражения могут быть представлены любыми операторами, включая пустые (то есть, вместо выражения можно поставить только символ точки с запятой).
Циклы while и for в большинстве случаев взаимозаменяемы. Так, представленный выше пример для цикла while , можно переписать в следующем виде:
const char str[] = «0123456789»;
char OddNums [5]; //Строка для хранения нечетных цифр
i = 0; //Индекс массива OddNums
if (( с % 2) == 1) OddNums[i++] = str[c];
В одних ситуациях удобнее применять циклы for , в других — while . Достоинством циклов for является более наглядная инициализация и организация изменения счетчика цикла, С другой стороны, циклы while более гибкие и обеспечивают больше возможностей для реализации нестандартных программных решений при организации повторяющихся вычислений.
Конструкция do — while
Кроме циклов while и for , в которых вначале выполняется проверка истинности условия цикла, и только потом управление передается блоку операторов цикла, в языке C имеется также конструкция do — while . Она отличается от первых двух тем, что в ней вначале выполняется блок операторов, и только потом проверяется выполнение условия. Другими словами, цикл do — while всегда выполняется как минимум один раз, вне зависимости от условия цикла.Цикл do — while имеет следующий синтаксис:
// Выполнение блока операторов цикла
Организация бесконечных циклов
Для организации бесконечного цикла в качестве условного выражения в конструкции while или do — while можно просто указать значение TRUE или 1:
while (1) блок_операторов ;
В случае циклов for это будет выглядеть следующим образом:
Операторы break и continue
Если в теле любого цикла встречается оператор break , управление тут же передается на оператор, следующий за оператором цикла, вне зависимости от истинности или неистинности условного выражения. При этом во вложенных циклах выход осуществляется не на самый верхний уровень вложенности, а лишь на один уровень вверх.
При выполнении оператора continue все находящиеся после него операторы блока пропускаются, а управление передается в начало цикла для следующей итерации. На практике операторы continue используются гораздо реже, чем операторы break , однако в сложных циклах, требующих принятия решений на основании многих факторов, использование операторов continue может быть весьма удобным.
Циклические конструкции
В Less нет стандартных циклов for или while . Однако, текущих возможностей формирования циклических конструкций хватает для всего круга задач, связанного с вёрсткой.
Как я уже говорил ранее, циклы строятся на принципе защиты примесей с помощью условного оператора ( when ). Таким образом, нужно понимать, что все циклы в Less построены на принципе рекурсий или, как напоминает нам JavaScript, цикле с предусловием while (выполнение условия проверяется перед тем, как войти в тело цикла).
Давайте подробно разберём пример, код которого формирует некоторое количество классов, жутко напоминающих простую сетку. Вот код с небольшими комментариями очевидных вещей:
@column-name: col; // Префикс класса сетки @column-count: 4; // Количество классов .generate-column(@i: 1) when (@i =< @column-count) < .@ -@ < width: @i * (100% / @column-count); > .generate-column(@i + 1); > .generate-column();
Основную работу выполняет примесь generate-column , принимающая на вход параметр i и защищённая с помощью ключевого слова when . Отсюда следует, что вся магия циклов в Less заключается в условной конструкции и рекурсивном вызове.
Так как примесь принимает на вход параметр i, который по сути является итерационной переменной, а также у примеси указано условие, при котором она будет работать, получается, что мы создаём простой вариант рекурсии. Она будет существовать до тех пор, пока значение переменной @i не сравняется с таковым у @column-count или не будет больше него.
Заглянем внутрь примеси. Здесь формируется имя селектора по правилу: префикс + номер итерации. Уже затем для этого селектора вычисляется значение ширины, как: 100% ширины, делённое на количество колонок и умноженное на шаг итерации. Обратите внимание на строку .generate-column(@i + 1) . Эта команда просит компилятор вызвать эту же примесь, но с увеличенным на единицу шагом итерации. Весь процесс повторяется вновь, но уже с увеличенным на единицу значением переменной @i . В этом и заключается магия.
Для наглядности процесса попробуем вместе с компилятором пройтись пару итераций:
/* Итерация 1 | @i: 1 | Новое значение @i: 2 */ .col-1 < width: 25%; > /* Итерация 2 | @i: 2 | Новое значение @i: 3 */ .col-1 < width: 25%; > .col-2 < width: 50%; > /* Итерация 3 | @i: 3 | Новое значение @i: 4 */ .col-1 < width: 25%; > .col-2 < width: 50%; > .col-3 < width: 75%; > /* Итерация 4 | @i: 4 | Новое значение @i: 5 */ .col-1 < width: 25%; > .col-2 < width: 50%; > .col-3 < width: 75%; > .col-4 < width: 100%; >
После того, как шаг итерации достигает максимально допустимого значения, происходит выход из рекурсии и компилятор продолжает бороздить красоты нашего кода. В нашем случае этот момент наступает на четвёртом шаге рекурсии, когда новое значение переменной @i равно 5, а максимальное число шагов итераций, заданное переменной @column-count , определено как 4.
Таким образом строятся и более сложные циклы, в которых участвуют несколько счётчиков, примесей или даже списков.
Обработка списка
Рассмотрим ещё один пример, где в цикле генерируются вспомогательные классы на основе списка. Этот пример вы уже встречали в главе 4, когда речь шла про списки (массивы).
Напомню его устрашающий код, который тогда мог повергнуть неподготовленного читателя в ужас:
// Настройки @column-name: col; @column-count: 4; @column-prefix: xs, sm, md, lg; // Генератор селекторов .generate-class(@indexCount, @indexPrefix: 1) when (@indexPrefix =< length(@column-prefix)) < // Получаем элемент списка @prefix: extract(@column-prefix, @indexPrefix); // Формируем селектор .@ -@ -@ < width: @indexCount * (100% / @column-count); > // Порождаем следующую итерацию .generate-class(@indexCount, @indexPrefix + 1); > // Генератор сетки .make-grid(@indexCount: 1) when (@indexCount =< @column-count) < // Вызываем генератор селекторов .generate-class(@indexCount); // Порождаем следующую итерацию .make-grid(@indexCount + 1); > // Вызываем генератор сетки .make-grid();
Теперь будем разбираться с ним вплоть до мелочей. Начнём с того, что перепишем весь этот код с Less на JavaScript. Зачем? — скоро все поймёте.
Понимание деталей
Если абстрагироваться от Less к JavaScript, то здесь объявлены две функции, которые, как кирпичики лего, позволяют строить лего-замок. Каждая функция выполняет свою простейшую задачу и, на практике, все функции можно было бы объединить в одну, конечно, при условии, что вам нравится запутанный код.
Для понимания происходящего, проведём параллель между обычным JavaScript-кодом и примесями в Less.
Настройки
В коде, приведённом ниже, объявляется объект columnOptions , хранящий настройки генератора сетки, такие как:
- Name — Имя столбца
- Count — Количество столбцов
- Prefix — Массив префиксов
// Настройки var columnOptions = < name: 'col', count: 4, prefix: ['xs', 'sm', 'md', 'lg'] >;
Если сравнивать с Less, то там настройки хранятся в переменных. Так, например, в JavaScript свойство объекта Prefix соответствует переменной @column-prefix в Less.
// Настройки @column-name: col; @column-count: 4; @column-prefix: xs, sm, md, lg;
Вызов
Так как генерировать сетку на JavaScript никто не будет, то и вывод результатов будет осуществляться в консоль:
// Вызываем генератор сетки console.log(makeGrid(columnOptions));
Разумеется, что в Less примесь вызывается стандартным образом:
// Вызываем генератор сетки .make-grid();
Итак, переходим вместе с кодом в примесь make-grid и отслеживаем работу дальше.
Генератор сетки
Код ниже представляет собой полный эквивалент примеси make-grid, переписанной на классический ванильный JavaScript.
Переменная consoleReturn представляет собой массив объектов, содержащих в себе пары ключей:
- Name — Имя текущего префикса (xs, sm..).
- Selector — Объект, содержащий информацию о колонке (имя и ширина), который возвращает функция generateSelector .
Далее в цикле производится проход по всем, указанным в настройках префиксам и на каждой итерации инициируется вызов функции, генерирующей информацию о селекторе.
Соответственно, вся полученная информация возвращается пользователю в консоль для анализа.
// Генератор сетки var makeGrid = function(o) < var consoleReturn = []; for (var index = 0; index < o.count; index++) < consoleReturn.push(< name: o.prefix[index], selector: generateSelector(o, index) >); > return consoleReturn; >;
Теперь снова посмотрим на нашу оригинальную примесь make-grid и разберёмся с тем, что там происходит:
// Генератор сетки .make-grid(@indexCount: 1) when (@indexCount =< @column-count) < // Вызываем генератор селекторов .generate-class(@indexCount); // Порождаем следующую итерацию .make-grid(@indexCount + 1); >
Если исключить тот факт, что в Less данные возвращаются автоматически и в рекурсивно вызываемой примеси generate-class , то можно с уверенностью сказать, что эта примесь работает так же, как и функция, написанная на JavaScript.
Вместо цикла for здесь используется рекурсия, которая работает до тех пор, пока итерационная переменная @indexCount меньше, либо равна количеству колонок, указанному в настройках.
На каждой итерации вызывается примесь генератора классов сетки, в которую передаётся переменная, указывающая номер итерации. Далее вызывается текущая примесь со значением итерационной переменной, увеличенной на единицу, чтобы породить рекурсию. То есть принцип действия полностью соответствует примеру, рассмотренному в начале этой части.
Проводя аналогию с функцией на JavaScript, можно выделить следующие наблюдения:
- Аналогом цикла for в Less является строка .make-grid(@indexCount + 1)
- Аналогом выражения цикла for в Less является условие when или, как его принято называть — выражение защиты примесей.
Перейдём к рассмотрению примеси, генерирующей селекторы.
Генератор селекторов
Ниже представлен эквивалент примеси generate-class на языке JavaScript, с той лишь разницей, что создавать рекурсию в JavaScript — кощунство, поэтому тут применяется стандартный цикл for .
// Функция генерации селекторов var generateSelector = function(o, indexCount) < var selectors = []; for (var index = 0; index < o.prefix.length; index++) < var name = o.name + '-' + o.prefix[indexCount] + '-' + index; var width = index * (100 / o.count) + '%'; selectors.push(< name: name, width: width >); > return selectors; >;
Эта функция принимает на вход объект настроек и номер текущей итерации. Массив selectors будет содержать имя и ширину селектора для всех префиксов из массива. Получается, что в нём будет храниться эквивалент CSS-кода:
.col-xs-1 < width: 25%; > .col-sm-1 < width: 25%; >
Углубляться в то, как он будет представлен не имеет смысла, так как главное здесь — понимать суть. В итоге, из этой функции будет возвращаться массив колонок одного префикса.
Снова обратим внимание на оригинальную less-примесь и проанализируем её действие:
// Генератор селекторов .generate-class(@indexCount, @indexPrefix: 1) when (@indexPrefix =< length(@column-prefix)) < // Получаем элемент списка @prefix: extract(@column-prefix, @indexPrefix); // Формируем селектор .@ -@ -@ < width: @indexCount * (100% / @column-count); > // Порождаем следующую итерацию .generate-class(@indexCount, @indexPrefix + 1); >
Как уже отмечалось выше, when играет роль выражения цикла, а последняя в примеси строка порождает новую итерацию этой же примеси, что эквивалентно новой итерации стандартного цикла for .
В отличии от JavaScript кода, примесь генерирует селектор и его свойства, а также возвращает их в виде CSS-кода по правилу:
Имя колонки + текущий префикс + номер итерации
Ширина колонки вычисляется тем же методом, что и в первом примере, описанном в этой части.
Таким образом, примесь будет рекурсивно выполняться до тех пор, пока не будут созданы селекторы для всех префиксов, указанных в переменной @column-prefix .
Результаты
После того, как компилятор пройдёт все итерации для каждой примеси, он вернёт сгенерированные селекторы на то место, где была вызвана управляющая примесь make-grid.
Если не изменять определённые ранее настройки, результат будет следующим:
.col-xs-1 < width: 25%; > .col-sm-1 < width: 25%; > .col-md-1 < width: 25%; > .col-lg-1 < width: 25%; > . .col-xs-4 < width: 100%; > .col-sm-4 < width: 100%; > .col-md-4 < width: 100%; > .col-lg-4 < width: 100%; >
Вывод JavaScript функций имеет приблизительно такой же вид с поправкой на то, что там данные не предоставляют ценности для CSS.
Выводы
Полностью рассмотрев два примера оценить всю природу циклических конструкций в Less нельзя. Зато можно понять их базовую сущность. Со временем вы научитесь составлять и более сложные конструкции, если это потребует поставленная задача. Да, циклы в Less имеют слегка непривычный вид для JavaScript-разработчиков, но разобравшись с ними раз и навсегда, проблем в дальнейшем не предвидится.
results matching » «
No results matching » «
Циклические конструкции
Для организации циклического выполнения программных блоков в языке Object Pascal используют циклические конструкции трех типов: for-do, while-do и repeat-until. Они отличаются характером начала и завершения цикла.
Читайте также
Циклические ссылки
Циклические ссылки Циклические ссылки являются источником практически любой утечки. Обычно скриптовые движки нормально отрабатывают с циклическими ссылками при помощи собственных сборщиков мусора, однако из-за некоторых неопределенностей их механизм эвристических
Управляющие конструкции
Управляющие конструкции Введение В четырех первых главах этой серии мы сконцентрировали свое внимание на синтаксическом анализе математических выражений и операций присваивания. В этой главе мы остановимся на новой и захватывающей теме: синтаксическом анализе и
20.3. Проблемы в конструкции Unix
20.3. Проблемы в конструкции Unix Операционная система Plan 9 «очищает» Unix, но добавляет лишь одну новую концепцию (частное пространство имен) к ее основному набору конструктивных идей. Однако есть ли серьезные проблемы в этих базовых идеях? В главе 1 рассматривалось несколько
20.3. Проблемы в конструкции Unix
20.3. Проблемы в конструкции Unix Операционная система Plan 9 «очищает» Unix, но добавляет лишь одну новую концепцию (частное пространство имен) к ее основному набору конструктивных идей. Однако есть ли серьезные проблемы в этих базовых идеях? В главе 1 рассматривалось несколько
Конструкции ветвления
Конструкции ветвления Конструкции ветвления осуществляют переход к одному из блоков программного кода на основании проверки некоторого условия. К ним относятся операторы if и
Итерационные конструкции
Итерационные конструкции Все языки программирования предлагают конструкции обеспечивающие возможность повторения блоков программного кода, пока не выполнено условие завершения повторений. Если у вас есть опыт программирования, то операторы цикла в C# будут для вас
Конструкции while и do/while
Конструкции while и do/while Цикл while оказывается полезным тогда, когда блок операторов должен выполняться до тех пор, пока не будет достигнуто заданное условие. Конечно, при этом требуется, чтобы в области видимости цикла while было определено условие окончания цикла, иначе вы
Программные конструкции
Программные конструкции В следующих разделах рассматриваются программные конструкции, распознаваемые в PSQL. Блоки BEGIN . END PSQL является структурированным языком. После объявления переменных процедурные операторы заключаются в операторные скобки BEGIN и END. В процессе
Циклические сэмплы
Циклические сэмплы Циклические сэмплы, или сэмплерные петли, – популярный тип сэмплов. Программные устройства воспроизведения сэмплов позволяют создавать полноценные музыкальные произведения путем соединения циклических сэмплов. Чтобы создать циклический сэмпл,
Конструкции XML
Конструкции XML Помимо элементов, атрибутов и текста, документы могут также содержать другие конструкции, такие как комментарии, инструкции по обработке и секции символьных данных. Эти базовые составляющие используются для того, чтобы гибко, но в четком соответствии со
18.2. Управляющие конструкции
18.2. Управляющие конструкции Почти все сценарии, за редким исключением, обладают свойством самоуправляемости. В чем состоит управление ходом выполнения сценария? Предположим, что в состав сценария включено несколько команд:#!/bin/sh# создание каталогаmkdir /home/dave/mydocs#
18.2.2. Циклические операторы
18.2.2. Циклические операторы Цикл, или итерация, — это процесс повторного выполнения наборов команд. В распоряжении пользователя имеется три вида операторов цикла: for loop Последовательная обработка значений до тех пор, пока не встретится окончание списка until
Циклические ссылки между модулями
Циклические ссылки между модулями Циклические ссылки модулей в интерфейсных частях запрещены. Например, следующая ситуация ошибочна: unit A; interface uses B; implementation end. unit B; interface uses A; implementation end. Таким образом, невозможно определить два общедоступных класса в разных модулях с