Функциональные компоненты цикла

Использование инструкции switch

Синтаксис инструкции switch

Инструкция switch

Вложенные инструкции if

Внутри каждой из ветвей инструкции if else может быть расположена другая инструкция if. Такие инструкции называются вложенными. Следует отметить, что большая глубина вложенности может приводить к ухудшению читабельности программы. Кроме того, может появиться специальная проблема, называемая проблемой висячего else. Такая проблема имеется, например, в инструкции if, структура которой приведена ниже.

if(выр1)
if(выр2)
инструкция1
else

инструкция2

При чтении приведенной выше конструкции возникает проблема, состоящая в том, что необходимо определить к какой из двух инструкций if единственное зарезервированное слово else. Иными словами, необходимо выяснить внешняя или внутренняя инструкция if является сокращенной. Эта проблема в языке Си решается следующим образом. Компилятор всегда относит слово else к ближайшему слову if, для которого еще нет ветви else. Учитывая все изложенное, можно сделать вывод о том, что в приведенном примере внешняя инструкция if является сокращенной, а внутренняя – полной.

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

if(выр1)
{
if(выр2)
инструкция1
}
else
инструкция2

В новой инструкции if внешняя инструкция является полной, а внутренняя – сокращенной.

Инструкция switch, иногда называемая переключателем, предназначена для организации многовариантного разветвления.

Инструкция switch может иметь сложную структуру. На самом верхнем уровне рассматриваемая инструкция состоит из двух конструктивных частей:

● Заголовок.

● Тело.

Заголовок инструкции switchимеет следующий формат:

switch(выр)

Здесь switch – зарезервированное слово, выр – выражение целого типа.

Телом может быть единственная инструкция языка Си, в качестве которой обычно используется составная инструкция.

Инструкции, входящие в состав тела переключателя switch, могут быть помеченными специальными метками. Метка отделяется от помечаемой ею инструкции двоеточием. В теле инструкции switch используются метки двух видов:

● label_case.

● label_default.

Метка вида label_case состоит из двух частей:

● зарезервированное слово case.

● Константное выражение целого типа.

Метка вида label_default состоит из одного зарезервированного слова default.

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

Опишем более детально процесс выполнения инструкции switch.

1. Вычисляется значение выражения выр, входящего в состав заголовка.

2. Если значение выражения выр совпадает со значением константного выражения одной из меток case, то управление передается инструкции тела, которая помечена этой меткой, а затем будут выполняться последовательно все оставшиеся инструкции тела переключателя.

3. Если значение выражения выр не совпадает со значением константного выражения ни одной метки, но имеется инструкция, помеченная меткой default, то управление передается инструкции, помеченной этой меткой.

4. Если значение выражения выр не совпадает со значением константного выражения ни одной метки и отсутствует инструкция, помеченная меткой default, то выполнение инструкции switch на этом заканчивается и управление передается инструкции, расположенной непосредственно за инструкцией switch.

Как правило, тело инструкции switch – составная инструкция, внутренние инструкции которой помечены метками case и default. После перехода на выбранную инструкцию остальные метки не влияют на выполнение тела переключателя. Для прекращения выполнения тела переключателя следует использовать инструкции перехода (обычно инструкцию break). Посмотрим, к чему может привести их отсутствие. Обратимся к программному коду, приведенному ниже, предполагая, что используемая в нем переменная n имеет тип int.

/* Использование инструкции switch, в теле которой отсутствуют
инструкции перехода */

switch(n)

{

case 1 : printf(“.”);
case 2 : printf(“..”);
case 3 : printf(“...”);
case 4 : printf(“....”);

}

Если перед выполнением приведенного выше фрагмента программы значение переменной n было равно 3, то при выполнении инструкции switch будет выведено семь точек, т.к. будут выполнены два последних вызова функции printf().

Чтобы в приведенном фрагменте программы выполнялся только тот вызов функции printf(), которому передано управление, необходимо все помеченные инструкции разделить инструкциями break. В результате получим следующий программный код:

/* Инструкция switch, в теле которой используются инструкции
break */
switch(n)
{
case 1 : printf(“.”);
break;
case 2 : printf(“..”);
break;
case 3 : printf(“...”);
break;
case 4 : printf(“....”);
break;
}

Теперь для любого значения величины n из отрезка [1, 4] будет выполняться только один вызов функции printf().

Заметим, что в ветви, соответствующей значению n == 4, использование инструкции break необязательно, но считается элементом хорошего стиля программирования.

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

● Инициализация (подготовка к первому выполнению цикла, возобновление цикла).

● Проверка условия нахождения в цикле.

● Рабочая часть цикла.

● Подготовка к очередному выполнению рабочей части цикла (продвижение цикла).

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

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

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

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

Все компоненты, кроме инициализации могут выполняться неоднократно, образуя так называемый контур цикла. Однократный “проход” цикла будем называть шагом. В качестве синонимов используются следующий понятия: итерация и виток цикла.

Разработку цикла следует начинать с его рабочей части. Необходимо выяснить, что же должен делать цикл? Ответ на этот вопрос должен носить общий характер. Он должен быть пригоден для произвольного шага цикла.

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

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

Рассмотрим пример организации циклического алгоритма. Пусть необходимо вычислить сумму квадратов первых “n” натуральных чисел. Введем следующие обозначения: i – очередное натуральное число, s – искомая сумма. Для нахождения суммы s необходимо выполнить “n” сложений. Действительно, s = 12 + 22 + .. + i2 +.. + n2 . Указанные действия можно осуществить за “n” шагов цикла, используя принцип накопления суммы. Для этого под s следует понимать текущее значение суммы, которое только после завершения работы цикла оказывается равным искомому значению суммы квадратов. Используя такой подход, в рабочей части цикла (символ 3) следует поместить инструкцию – присваивание языка Си следующего вида:

s += i * i; /* s = s + i * i ; */

 

Для правильной работы цикла переменные i и s необходимо инициализировать следующим образом (символ 1):

i = 1;
s = 0;

В символе 4 для правильного продвижения цикла следует поместить инструкцию инкремента переменной i:

i++;

Для обеспечения n кратного выполнения цикла в символе 2 следует проверять отношение: i <= n .