КИТ и Э КБГУ Понедельник, 06.05.2024, 15:15
Приветствую Вас Гость | RSS
Меню сайта

Наш опрос
Оцените мой сайт
Всего ответов: 118

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

Управляющие конструкции

  1. Конструкция if-else…Конструкция else-if…
  2. Переключатель switch.
  3. Циклы for, while, do-while. Операторы break, continue, и return.

Лабораторная работа 2. Программирование с использованием управляющих конструкций: if-else…, else-if…

Лабораторная работа 3. Программирование с использованием управляющих конструкции switch

Лабораторная работа 4. Программирование с использованием цикла for

Лабораторные работы 5-6. Программирование с использованием циклов while/do-while

1. Конструкция if-else… Конструкция else-if

Инструкции и блоки

Выражение, скажем х = 0, или i++, или printf (…) , становится инструкцией, если в конце его поставить точку с запятой, например:

х = 0;

i++;

printf (…);

В Си точка с запятой является заключающим символом инструкции, а не разделителем, как в языке Паскаль.

Фигурные скобки { и } используются для объединения объявлений и инструкций в составную инструкцию, или блок, чтобы с точки зрения синтаксиса эта новая конструкция воспринималась как одна инструкция. Фигурные скобки, обрамляющие группу инструкций, образующих тело функции, — это один пример; второй пример — это скобки, объединяющие инструкции, помещенные после if, else, while или for. (Переменные могут быть объявлены внутри любого блока, об этом разговор пойдет в главе 4.) После правой закрывающей фигурной скобки в конце блока точка с запятой не ставится.

 Конструкция if-else

Инструкция if-else используется для принятия решения. Формально ее синтаксисом является:

if (выражение)

инструкция1

else

инструкция2

причем else-часть может и отсутствовать. Сначала вычисляется выражение, и, если оно истинно (т. е. отлично от нуля), выполняется инструкция1. Если выражение ложно (т. е. его значение равно нулю) и существует else-часть, то выполняется инструкция2.

Так как if просто проверяет числовое значение выражения, условие иногда можно записывать в сокращенном виде. Так, запись

if (выражение)

короче, чем

if (выражение ! = 0)

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

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

Например, в

if (n > 0)

if (а > Ь)

z = а;

else

z = b;

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

if (n > 0) {

if (a > b)

z = а;

}

else

z = b;

Ниже приводится пример ситуации, когда неоднозначность особенно опасна:

if (n >= 0)

for (i = 0; i < n; i++)

if (s[i] > 0) {

printf ( " . . . " ) ;

return i;

}

else /* НЕВЕРНО */

printf("ошибка - отрицательное n\n");

Компилятор не воспримет эту информацию и отнесет else к внутреннему if. Искать такого рода ошибки особенно тяжело. Здесь уместен следующий совет: вложенные if обрамляйте фигурными скобками. Кстати, обратите внимание на точку с запятой после z = а в

if (a > b)

z = а;

else

z = b;

Здесь она обязательна, поскольку по правилам грамматики за if должна следовать инструкция, а выражение-инструкция вроде z = а; всегда заканчивается точкой с запятой.

Конструкция else-if

Конструкция

if (выражение)

инструкция

else if (выражение)

инструкция

else if (выражение)

инструкция

else if (выражение)

инструкция

else

инструкция

встречается так часто, что о ней стоит поговорить особо. Приведенная последовательность инструкций if — самый общий способ описания многоступенчатого принятия решения. Выражения вычисляются по порядку; как только встречается выражение со значением "истина", выполняется соответствующая ему инструкция; на этом последовательность проверок завершается. Здесь под словом инструкция имеется в виду либо одна инструкция, либо группа инструкций в фигурных скобках. Последняя else-часть срабатывает, если не выполняются все предыдущие условия. Иногда в последней части не требуется производить никаких действий, в этом случае фрагмент

else

инструкция

можно опустить или использовать для фиксации ошибочной ("невозможной") ситуации.

2. Переключатель switch

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

switch (выражение) {

case конст-выр: инструкции

case конст-выр: инструкции

default: инструкции

}

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

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

#include <stdio.h>

main() /* подсчет цифр, символов-разделителей и прочих символов */

{

int с, i, nwhite, nother, ndigit[10];

nwhite = nother = 0;

for (i = 0; i < 10; i++)

ndigit[i] = 0;

while ((c = getcharO) != EOF) {

switch (c) {

case '0': case '1': case '2': case '3': case '4':

case '5': case '6': case '7': case '8': case '9':

ndigit[c - '0' ]++;

break;

case ' ':

case '\n':

case '\t':

nwhite++;

break;

default:

nother++;

break;

}

}

printf ("цифр =");

for (i= 0; i < 10; i++)

printf (" %d", ndigit[i]);

printf (", символов-разделителей = %d, прочих = %d\n", nwhite, nother);

return 0;

}

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

Инструкции break и return — наиболее распространенные средства выхода из переключателя. Инструкция break используется также для принудительного выхода из циклов while, for и do-while (мы еще поговорим об этом чуть позже). "Сквозное" выполнение ветвей case вызывает смешанные чувства. С одной стороны, это хорошо, поскольку позволяет несколько ветвей case объединить в одну, как мы и поступили с цифрами в нашем примере. Но с другой это означает, что в конце почти каждой ветви придется ставить break, чтобы избежать перехода к следующей. Последовательный проход по ветвям — вещь ненадежная, это чревато ошибками, особенно при изменении программы. За исключением случая с несколькими метками для одного вычисления, старайтесь по возможности реже пользоваться сквозным проходом, но если уж вы его применяете, обязательно комментируйте эти особые места.

Замечание: даже в конце последней ветви (после default в нашем примере) помещайте инструкцию break, хотя с точки зрения логики в ней нет никакой необходимости. Но эта маленькая предосторожность спасет вас, когда однажды вам потребуется добавить в конец еще одну ветвь case.

3. Циклы while и for

Мы уже встречались с циклами while и for. В цикле

while (выражение)

инструкция

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

Инструкция for

for (выр1; выр2; выр3)

инструкция

эквивалентна конструкции

выр1;

while (выр2) {

инструкция

выр3;

}

С точки зрения грамматики три компоненты цикла for представляют собой произвольные выражения, но чаще выр1 и выр3 — это присваивания или вызовы функций, а выр2 — выражение отношения. Любое из этих трех выражений может отсутствовать, но точку с запятой опускать нельзя. При отсутствии выр1 или выр3 считается, что их просто нет в конструкции цикла; при отсутствии выр2 предполагается, что его значение как бы всегда истинно. Например,

for (;;)

{…}

есть "бесконечный" цикл, выполнение которого, вероятно, прерывается каким-то другим способом, например с помощью инструкций break или return.

Какой цикл выбрать: while или for — это дело вкуса.

Цикл do-while

В циклах while и for проверка условия окончания цикла выполняется наверху. В Си имеется еще один вид цикла, do-while, в котором эта проверка в отличие от while и for делается внизу после каждого прохождения тела цикла, т. е. после того, как тело выполнится хотя бы один раз. Цикл do while имеет следующий синтаксис:

do

инструкция

while (выражение);

Сначала выполняется инструкция, затем вычисляется выражение. Если оно истинно, то инструкция выполняется снова и т. д. Когда выражение становится ложным, цикл заканчивает работу. Цикл do-while эквивалентен циклу repeat-until в Паскале с той лишь разницей, что в первом случае указывается условие продолжения цикла, а во втором — условие его окончания.

Опыт показывает, что цикл do-while используется гораздо реже, чем while и for .

4. Инструкции break и continue

Иногда бывает удобно выйти из цикла не по результату проверки, осуществляемой в начале или в конце цикла, а каким-то другим способом. Такую возможность для циклов for, while и do-while, а также для переключателя switch предоставляет инструкция break. Эта инструкция вызывает немедленный выход из самого внутреннего из объемлющих ее циклов или переключателей.

Пример 2. Следующая функция, trim, удаляет из строки завершающие пробелы, табуляции, символы новой строки; break используется в ней для выхода из цикла по первому обнаруженному справа символу, отличному от названных.

/* trim: удаляет завершающие пробелы, табуляции и новые строки */

int trim(char s[])

{

int n;

for (n = strlen(s)-1; n >= 0; n--)

if (s[n] != ' ' && s[n] != '\t' && s[n] != '\n')

break;

s[n+1] = '\0';

return n;

}

С помощью функции strlen можно получить длину строки. Цикл for просматривает его в обратном порядке, начиная с конца, до тех пор, пока не встретится символ, отличный от пробела, табуляции и новой строки. Цикл прерывается, как только такой символ обнаружится или n станет отрицательным (т. е. вся строка будет просмотрена). Убедитесь, что функция ведет себя правильно и в случаях, когда строка пуста или состоит только из символов-разделителей.

Инструкция continue в чем-то похожа на break, но применяется гораздо реже. Она вынуждает ближайший объемлющий ее цикл (for, while или do-while) начать следующий шаг итерации. Для while и do-while это означает немедленный переход к проверке условия, а для for — к приращению шага. Инструкцию continue можно применять только к циклам, но не к switch. Внутри переключателя switch, расположенного в цикле, она вызовет переход к следующей итерации этого цикла. Вот фрагмент программы, обрабатывающий только неотрицательные элементы массива a (отрицательные пропускаются).

for ( i = 0 ; i < n; i++) {

if (a[i] < 0) /* пропуск отрицательных элементов */

continue;

/* обработка положительных элементов */

}

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

Инструкция goto и метки

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

for (…)

for (…) {

if (disaster) /* если бедствие */

goto error; /* уйти на ошибку */

}

error: /* обработка ошибки */

ликвидировать беспорядок

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

for (i = 0 ; i < n; i++)

for (j = 0; j < m; j++)

if (a[i] == b[j])

goto found;

/* нет одинаковых элементов */

found:

/* обнаружено совпадение: a[i] == b[j] */

Программу нахождения совпадающих элементов можно написать и без goto, правда, заплатив за это дополнительными проверками и еще одной переменной:

found = 0;

for (i = 0; i < n && !found; i++)

for (j = 0; j < m && !found; j++)

if (a[i] == b[j])

found = 1;

if (found)

/* обнаружено совпадение: a[i-1] == b[j-1] */

else

/* нет одинаковых элементов */

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

 

Пример 3. Найдем  сумму отрицательных значений функции sin(x) для x меняющегося от xn до xk с шагом h. Следующая программа решает эту задачу:

 

    #include <math.h>

    #include <stdio.h>

 

    /* нахождение суммы отрицательных значений синуса */

 

    void main( void )

    { 

    double xn, xk, h, x, sum;

     printf( "Введите xn, xk, h \n" );

     scanf( "%lf%lf%lf", &xn, &xk, &h );

     x = xn;

     sum = 0;                                                                      /* обнуление суммы */

     while( x <= xk )

       {  if( sin(x)<0 ) sum += sin(x);                                      /* вычисление суммы */

          x += h;        }

       printf( "Сумма  = %lf\n", sum);

    }

 

Пример 4. Следующая программа устанавливает факт наличия отрицательных значений sin(x) для x меняющегося от xn до xk c шагом h :

    #include <math.h>

    #include <stdio.h>

    /* использование флагов */

    void main( void )

    {  double xn, xk, h, x;

       int    minus; /* флаг */

       printf( "Введите xn, xk, h \n" );

       scanf( "%lf%lf%lf", &xn, &xk, &h );

       x = xn;

       minus = 0;                                                        /* предполагается, что нет не одного  отрицательного значения */

       while( x <= xk )

       { if( sin(x) < 0 ) minus = 1;

          x += h;    }

       if( minus ) printf( "Имеются отрицательные значения\n" );

       else printf( "Все синусы положительные\n" );

    }

 

Пример 5. Следующая программа вычисляет sin(x),  cos(x),  tan(x) в зависимости от выбора пользователя:

#include <math.h>

#include <stdio.h>

/* Организация простейшего меню */

void main ( void )

{   int loop;                                                /* Флаг, который сигнализирует о конце работы */

   int choice;                                             /* Текущий выбор пункта меню */

   double fun, x;                                       /* Значения функции и аргумента */

   printf( "\nВведите аргумент x=" );

   scanf( "%lf", &x );

   loop=1;

   while ( loop )

   {

      printf ( "\n   Введите номер функции:\n" );

      printf ( "1. sin(x)\n2. cos(x)\n" );

      printf ( "3. tan(x)\n4. Конец работы\n" );

      scanf  ( "%d", &choice );

      if      (choice==1) fun=sin(x);

      else if (choice==2) fun=cos(x);

      else if (choice==3) fun=tan(x);

      else if (choice==4) { loop=0; continue; }

      else    { printf( "Неверный выбор\n" ); continue; }

      printf( "Значение функции %lf\n", fun );

   }

}

 

Вход на сайт

Поиск

Календарь
«  Май 2024  »
ПнВтСрЧтПтСбВс
  12345
6789101112
13141516171819
20212223242526
2728293031

Архив записей

Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz

  • Copyright Fatima_Zh © 2024Бесплатный хостинг uCoz