Программирование на языке C в Microsoft Visual Studio 2010

Организация циклов в языке С

Разбить на страницы
Показывать лекцию целиком

Теоретическая часть

Операторы цикла относятся к управляющим конструкциям всякого языка программирования. Управляющие операторы и конструкции языка задают порядок, в котором выполняются вычислительные операции программы [3.1].

3.1. Оператор while

Изучение операторов цикла начнем с оператора while. Цикл while имеет следующий формат (синтаксис) записи [3.2]:

while (expression)
program statement;

Производится расчет выражения expression, заключенного в круглые скобки. Если в результате расчета выражения expression получается истинный результат ( TRUE ), то выполняется утверждение program statement, следующее непосредственно за закрывающей круглой скобкой. После выполнения этого утверждения вновь рассчитывается выражение expression. Если в результате расчета будет TRUE, то вновь будут выполнены утверждения program statement. Цикл повторяется до тех пор, пока в результате расчета выражения expression (в круглых скобках оператора while ) не будет получено значение FALSE (ложный), которое является признаком окончания цикла, после чего выполнение программы продолжается с утверждения, следующего за утверждением program statement. Когда требуется выполнить группу утверждений, то она (группа) располагается в фигурных скобках:

while (expression)
{
program statement;
program2 statement2;
program3 statement3;
...
}

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

Очевидно, что неверное задание выражения expression может привести к бесконечному циклу (к зацикливанию).

3.2. Оператор for

Оператор цикла for имеет следующий формат записи:

for (init_expression; loop_condition; loop_expression)
program statement;

Три выражения, заключенные в круглые скобки оператора цикла for, задают условия выполнения программного цикла [3.2].

Первый параметр init_expression используется для задания начального значения цикла.

Второй компонент loop_condition определяет условие или условия, в соответствии с которыми будет происходить выход из цикла. Повторение будет происходить до тех пор, пока это условие (или условия) выполняются. Если условие не выполняется, то цикл немедленно заканчивается.

Третий параметр loop_expression выполняется каждый раз, когда заканчивается обработка тела цикла, т.е. program statement.

Чаще всего выражения init_expression и loop_expression являются операторами присваивания или вызовами функций, а второе выражение loop_condition – выражением отношения или логическим выражением [3.1]. Любую из трех частей можно опустить, но точки с запятыми должны остаться на своих местах. Если опустить init_expression или loop_expression, то соответствующие операции не будут выполняться. Если же опустить проверку условия loop_condition, то по умолчанию считается, что условие продолжения цикла всегда истинно, и тогда цикл станет бесконечным (произойдет зацикливание).

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

for (init_expression; loop_condition; loop_expression)
{
program1 statement1;
program2 statement2;
program3 statement3;
...
}

В представленном случае тело цикла находится в фигурных скобках.

Конструкция цикла, реализованная оператором for, может быть выполнена также и оператором while следующим образом [3.1]:

init_expression;
while (loop_condition)
{
program statement;
loop_expression;
}

Исключением является применение операции continue.

Операторы отношения перечислены в табл. 3.1.

Операторы отношения языка программирования С
№ п/п Оператор Значение
1) == Равно
2) != Не равно
3) < Меньше
4) <= Меньше или равно
5) > Больше
6) >= больше или равно

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

3.3. Оператор do–while

Рассмотренные операторы цикла while и for производят проверку условия выполнения цикла до начала выполнения тела цикла [3.1]. Поэтому тело цикла может ни разу не выполниться, если с самого начала результатом расчета условия выполнения цикла будет значение FALSE (ложь). В случае необходимости производить проверку условия выполнения цикла после тела цикла (т.е. когда выполняется хотя бы одно предписанное действие в теле цикла) прибегают к циклу do–while.

Оператор цикла do–while имеет следующий формат записи [3.2]:

do
program statement;
while (loop_condition);

Выполнение цикла do–while происходит следующим образом: сначала выполняется утверждение program statement, затем производится проверка условия выполнения цикла loop_condition с помощью оператора while. Если результатом проверки будет значение TRUE (истина), то выполнение цикла продолжится, и утверждение program statement всякий раз будет выполняться вновь. Повторение цикла будет продолжаться до тех пор, пока в результате проверки условия выполнения цикла loop_condition будет получаться значение TRUE. Когда в результате проверки условия будет вычислено значение FALSE (ложь), то выполнение цикла прекратится и произойдет переход к утверждению (следующему фрагменту программы), непосредственно следующему за циклом [3.2].

Таким образом, цикл do–while гарантированно выполнится хотя бы один раз.

В случае выполнения нескольких утверждений используются фигурные скобки для выделения тела цикла:

do {
program1 statement1;
program2 statement2;
program3 statement3;
... } while (loop_condition);

Оператор цикла while называется оператором цикла с предусловием, оператор цикла for называется оператором цикла с параметром, оператор цикла do–while называется оператором цикла c постусловием.

Практическая часть

Рассмотрим примеры программ с операторами циклов while, for и do–while.

Пример 1. Напишите программу вывода на экран пользователя целых положительных чисел с помощью оператора while. Начальное и последнее число должно задаваться пользователем с клавиатуры.

Программный код решения примера:

#include <stdio.h>
#include <conio.h>

int main(void)
 {
int i, j = 0, n;
printf("\n\t Enter the primary natural number: ");
scanf_s("%d", i);
printf("\t Enter the last natural number: ");
scanf_s("%d", n);

printf("\n\t The numbers are:");
while (i <= n) {
printf("\n\t %3d", i);
++i;
++j; 
}
printf("\n\t Total numbers: %d\n", j);
	
printf("\n Press any key: ");
	_getch();
	return 0;
 }
(рис 3.1) Результат выполнения программы с вводом целых чисел

Возможный результат выполнения программы показан на рис 3.1.

В программе использована функция scanf_s(), принятая в MS Visual Studio. В программе применено инкрементирование переменных, принятое в языке С, а именно ++i или ++j означает, что переменные увеличиваются на единицу. При этом знаки "++" могут располагаться перед именем переменной или после. Отличие в том, что ++i – это значение переменной после увеличения, а i++ – сначала переменная имеет заданное значение, а потом происходит ее увеличение. Для переменных цикла обе формы равнозначны.

Условием цикла является то, что пока переменная i меньше или равна переменной n (предполагается, что n больше начального значения i ), то будут выполняться действия (печать и увеличение переменной j ), заложенные в теле цикла. Расчет выражения, заключенного в круглые скобки оператора, предназначен для проверки нестрогого неравенства переменной i по отношению к переменной n. Если это неравенство выполняется, то в теле цикла происходят печать и увеличение (инкрементирование) переменных i, j.

Задание 1

  • Предусмотрите ввод только отрицательных чисел.
  • Предусмотрите ввод только неотрицательных чисел.
  • Предусмотрите вывод чисел и их порядковые номера (т.е. в два столбца).
  • Предусмотрите вывод чисел на консоль в виде строки.
  • Предусмотрите ввод и вывод только вещественных чисел.
  • С учетом предыдущего пункта предусмотрите вывод чисел и их порядковые номера (т.е. в два столбца).
  • Рассмотреть варианты форм инкрементирования. Выполните вывод на консоль.
  • Пример 2. Напишите программу посимвольного ввода предложения "Hello, world" и подсчитать число символов в нем (включая запятую и пробел).

    Программный код решения примера:

    #include <stdio.h>
    #include <conio.h>
    
    int main(void)
    {
    	int c, i = 0;
    
    printf("\n Enter symbol-by-symbol the offer \"Hello, world\",\n  press twice Ctrl+Z and press Enter:\n");
    printf("\t");
    
    while ((c = getchar()) != EOF)
    {
    printf("\t");
    c = getchar();
    ++i;
    }
    
    printf("\n\t The number of characters: %d\n", i);
    	
         printf("\n Press any key: ");
    	_getch();
    	return 0;
    }

    В программе ввод символьных данных должен завершиться комбинацией клавиш Ctrl+Z, что будет соответствовать окончанию ввода (файла), т.е. EOF. Оператор цикла while будет выполняться до тех пор, пока не встретится так называемый конец файла EOF. В предложении \"Hello, world\" два обратных слэша включены для вывода на консоль двойных кавычек.

    Функции printf("\t") осуществляют табуляцию вводимых символов. Подсчет числа вводимых символов выполняется с помощью переменной цикла (счетчика) i, которая инкрементируется в теле цикла.

    Заголовочный файл #include <conio.h> служит для поддержания консольного ввода-вывода для функции _getch(). Без него при компиляции программы могут выводиться предупреждения, хотя программа с предупреждениями работает.

    Результат выполнения программы показан на рис 3.2.

    (рис 3.2) Выполнение программы посимвольного ввода данных

    Задание 2

  • В программу введите комментарии с помощью символов // и /*...*/.
  • В качестве вводимых символов используйте буквы своей фамилии (буквами латинского алфавита). В отчет вставьте полученный результат.
  • В качестве вводимых символов использовать свою фамилию и имя. В отчет вставьте полученный результат.
  • Сделайте вывод своей фамилии и имени по главной диагонали дисплея.
  • В качестве символов введите числа от 1 до (2+Х), где Х – номер компьютера, за которым выполняется лабораторная работа. В отчет вставьте полученный результат.
  • Выполните дублирование символов с помощью функции putchar(), которая отображает символы на экране пользователя.
  • Примечание. Прототип функции putchar() имеет следующий вид:

    #include <stdio.h>
    int putchar (int ch);

    Пример 3. Напишите программу табличного вывода строчных букв латинского алфавита и их десятичных кодов с помощью оператора цикла for.

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

    Программный код решения примера:

    #include <stdio.h>
    #include <conio.h>
    int main(void){
    	int j = 1;
    	char a = 'a';
    	
    	printf("\n  Table code characters:\n");
    for ( ; a <= 'z'; ++a)
    	printf("\n %4d) %2c: code%4d", j++, a, a);
    
    	printf("\n\n Press any key: ");
    	_getch();
    	return 0;
    }

    Результат выполнения программы показан на рис 3.3.

    (рис 3.3) Таблица десятичных кодов букв латинского алфавита

    Форматированный вывод данных предусматривает выравнивание по правому краю, для чего предусматриваются числовые спецификаторы типа %4d и %2c для целых чисел и символов в функции printf().

    Задание 3

  • Примените префиксную форму инкрементирования переменной j.
  • Инкрементирование переменной j создайте отдельно в теле цикла.
  • Инициализацию переменной j начните с нуля. Результат выполнения программы должен быть тот же самый, что и в приведенной программе.
  • Напишите программу для вывода кодов букв из заданного диапазона на усмотрение пользователя, например, от 'j' до 'w'.
  • В цикле for заполните все поля.
  • Напишите программу для вывода кодов букв латинского алфавита прописных и строчных букв в одной таблице.
  • Выведите буквы своей фамилии и коды этих букв.
  • Напишите программу расчета значений функции распределения потока Эрланга 4-го порядка с параметром $$\lambda$$ = 2.3 на отрезке времени от 0 до 5 (условных единиц) с шагом 0.2:

    $$F_k(t)=1-\sum\limits_{j=0}^{k}\frac{(\lambda t )^j}{j!}{e}^{-\lambda t}.$$

    Программный код решения примера:

    #include <stdio.h>
    #include <conio.h>
    #include <math.h>
    
    int main(void)
     {
    	int j, f, k = 4;
    	double F, Lt, s, t = 0.0, Tend = 5.0;
    	float L = 2.3F;
    		
    printf("\n Erlang function of order %d, Lambda = %1.2f:\n\n", k, L);
    		
    for ( ; t <= Tend; t += 0.2) {
    s = 0.0; f = 1; Lt = 1.0;
    for (j = 1; j <= k; ++j) {
    f *= j;
    Lt *= (L*t);
    s += (Lt/f)*exp(-L*t);
    }
    F = 1 - exp(-L*t) - s;
    printf("\t %lg\n", F);
    }
    	printf("\n\n Press any key: ");
    	_getch();
    	return 0;
    }

    В программе использованы вложенные циклы for. Применены специфические условия изменения переменных (но характерных для языка С ):

    t += 0.2;      /* t  =  t + 0.2; */
         f *= j;        /* f  =  f * j; */
        Lt *= (L*t);    /* Lt  =  Lt * (L*t); */

    Вычисление факториала выполнено с помощью произведения и выделения отдельного слагаемого суммы, когда рассчитывается 0!

    В программе также предусмотрено накопление суммы для каждого шага времени t. Для расчета экспоненты в заголовок программы включена библиотека математических функций #include <math.h>.

    Результат выполнения программы показан на рис 3.4.

    (рис 3.4) Расчет функции распределения Эрланга 4-го порядка

    Задание 4

  • В заголовке внешнего цикла for добавьте первое поле и устраните третье поле.
  • Предусмотрите вывод количества значений рассчитанной функции Эрланга.
  • Предусмотрите ввод параметров программы, а именно: порядок потока Эрланга k, параметр $$\lambda$$, конечную величину временного интервала, шаг по времени.
  • Пример 5. Вычислите с точностью до "машинного нуля" значение суммы числового ряда:

    $$\frac 1 {1\cdot 2\cdot 3}+ \frac 1 {2\cdot 3\cdot 4}+\frac 1 {3\cdot 4\cdot 5}+\frac 1 {4\cdot 5\cdot 6}+\cdots$$

    Программный код решения примера:

    #include <stdio.h>
    #include <conio.h>
    
    int main(void)
     {
       double denom;
       double sum1 = 0.0, sum2 = 0.0;
       int k = 1;
       denom = k * (k + 1) * (k + 2); // знаменатель ряда
    
    	do {
    	sum1 = sum2;
    	sum2 += 1.0 / denom;
    	denom = denom / k * (k + 3);
    	++k;
    	} while (sum1 < sum2);
    
    printf("\n\t The amount of numerical series: %lg\n", sum2);
    	
    	printf("\n Press any key: ");
    	_getch();
    	return 0;
    }

    В приведенной программе сумма вычисляется как значение переменной sum2. Ее предыдущее значение сохраняется в переменной sum1. Так как приближенное значение с добавлением неотрицательных слагаемых не уменьшается, условием продолжения цикла служит отношение sum1 < sum2 (поскольку растет знаменатель denom ). Когда при добавлении очередного слагаемого значение суммы остается неизменным (за счет конечной разрядной сетки для представления вещественных чисел), нарушается условие sum1 < sum2 и цикл прекращается. Таким образом, конечность разрядной сетки представления вещественных чисел в компьютере определяет собой "машинный нуль".

    Инициализация знаменателя сделана до начала цикла. Форматный вывод результата выполнен с помощью спецификатора символа "l".

    Результат выполнения программы показан на рис 3.5.

    (рис 3.5) Результат подсчета суммы бесконечного ряда

    Задание 5

  • Подсчитайте число итераций цикла для подсчета суммы ряда.
  • Напишите программу с нулевой инициализацией переменной k.
  • Напишите условие "загрубения" результата подсчета суммы ряда.
  • В программе примените тип float вместо типа double. Проанализируйте результат.
  • Вместо оператора цикла do–while примените иной оператор цикла.
  • Пример 6. Произведите реверс цифр заданного целого числа, вводимого с клавиатуры пользователем.

    Задача заключается в том, чтобы, например, число 123 переписать как 321.

    Программный код решения примера:

    #include <stdio.h>
    #include <conio.h>
    
    int main(void)
     {
    	long int x, r;
    
    	printf("\n Enter an integer: ");
    	scanf_s("%ld", x);
    
    	printf("\n Reverse-digit number %ld:\n\n\t", x);
    
    	do {
    	r = x % 10;
    	printf(" %ld", r);
    	x = x / 10;
    	} while ( x != 0);
    
    	printf("\n\n Press any key: ");
    	_getch();
    	return 0;
    }

    В программе применена операция арифметическая операция деления по модулю, которая имеет символ процента, т.е. "%". Любой остаток, получающийся в результате деления целых чисел, будет отброшен [3.2]. В шкале старшинства оператор деления по модулю имеет приоритет, равный приоритету операторов умножения и деления. Переменные, используемые в программе, объявлены как длинные числа, поэтому применен тип long int (или long ). В некоторых компиляторах имеются отличия между типами int и long int в смысле максимально поддерживаемого значения числа.

    Результат выполнения программы показан на рис 3.6.

    (рис 3.6) Результат программы по реверсу числа

    Задание 6

  • Предусмотрите подсчет итераций заданного цикла.
  • Напишите программу по реверсу числа с оператором цикла while. Протестируйте обе программы, в том числе по вводу числа 0.
  • Определите максимальное число вида 123...987..., для которого еще можно применить тип long int.
  • Пример 7. На основе только оператора цикла for напишите программу по выводу "горки" заглавных букв, симметрично убывающих к букве, введенной пользователем. Также на основе оператора цикла for предусмотрите защиту от неправильного ввода.

    Программный код решения примера:

    #include <stdio.h>
    #include <conio.h>
    
    int main (void) {
    	int p = 0;
         char ch = 'A'; 
         char i, j, k, ch2, kk, chA;
         chA = ch;
    
    printf("\n   Enter a capital letter between \"A\" and \"S\": ");
    scanf_s("%c", ch2, sizeof(char));
    
    for(chA -= 1; chA >= ch2; chA-- )
     {
    	printf("\n   Error! Press any key: ");
    	_getch();
    	return -1;
     }
    
    for (kk = 'S'+1; kk  <= ch2; kk++) 
    {
    printf("\n   Error! Press any key: ");
    	_getch();
         return -1;
    }
    
    k = ch2;
    for ( kk = ch; kk <=  k; kk++)
     {
    		printf("\n ");
    
    for (ch2 = ch; ch2 <= k-p ; ch2++) 		
    			printf("  ");	
    
    for (j = ch; j <= kk ; j++)  
    		printf(" %c", j);	
    	for (i = kk; i > ch; i-- )
    			printf(" %c", i-1);
    	p++;
    		
    }
        printf("\n\n Press any key: ");
    	_getch();
    	return 0;
    }

    Пример выполнения программы показан на рис 3.7.

    (рис 3.7) Пример горки букв

    Задание 7

  • Напишите программу на основе только оператора цикла for по выводу перевернутой горки букв, а также "левой" и "правой" горки.
  • Напишите программу на основе только оператора цикла for по выводу "ромба" букв, относительно введенной буквы.
  • Напишите программу по выводу горки букв только на основе оператора цикла while.
  • Контрольные вопросы

  • Как организуются составные операторы циклов в языке С?
  • Как организуются вложенные циклы в языке С?
  • В каких случаях может произойти зацикливание при использовании оператора цикла с предусловием?
  • В каких случаях может произойти зацикливание при использовании оператора цикла с постусловием?
  • Сколько условий требуется для работы оператора цикла с параметром?
  • Чем отличаются префиксное и постфиксное инкрементирование и декрементирование?
  • Какое различие в операторах цикла между префиксным и постфиксным инкрементированием?
  • Сколько операторов отношения в языке С? Перечислите их.
  • Как реализуется взаимозаменяемость операторов цикла while и for?
  • В чем сходство и различие между циклами с предусловием и с постусловием?
  • Страницы:

    Теоретическая часть

    Операторы цикла относятся к управляющим конструкциям всякого языка программирования. Управляющие операторы и конструкции языка задают порядок, в котором выполняются вычислительные операции программы [3.1].

    3.1. Оператор while

    Изучение операторов цикла начнем с оператора while. Цикл while имеет следующий формат (синтаксис) записи [3.2]:

    while (expression)
    program statement;

    Производится расчет выражения expression, заключенного в круглые скобки. Если в результате расчета выражения expression получается истинный результат ( TRUE ), то выполняется утверждение program statement, следующее непосредственно за закрывающей круглой скобкой. После выполнения этого утверждения вновь рассчитывается выражение expression. Если в результате расчета будет TRUE, то вновь будут выполнены утверждения program statement. Цикл повторяется до тех пор, пока в результате расчета выражения expression (в круглых скобках оператора while ) не будет получено значение FALSE (ложный), которое является признаком окончания цикла, после чего выполнение программы продолжается с утверждения, следующего за утверждением program statement. Когда требуется выполнить группу утверждений, то она (группа) располагается в фигурных скобках:

    while (expression)
    {
    program statement;
    program2 statement2;
    program3 statement3;
    ...
    }

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

    Очевидно, что неверное задание выражения expression может привести к бесконечному циклу (к зацикливанию).

    3.2. Оператор for

    Оператор цикла for имеет следующий формат записи:

    for (init_expression; loop_condition; loop_expression)
    program statement;

    Три выражения, заключенные в круглые скобки оператора цикла for, задают условия выполнения программного цикла [3.2].

    Первый параметр init_expression используется для задания начального значения цикла.

    Второй компонент loop_condition определяет условие или условия, в соответствии с которыми будет происходить выход из цикла. Повторение будет происходить до тех пор, пока это условие (или условия) выполняются. Если условие не выполняется, то цикл немедленно заканчивается.

    Третий параметр loop_expression выполняется каждый раз, когда заканчивается обработка тела цикла, т.е. program statement.

    Чаще всего выражения init_expression и loop_expression являются операторами присваивания или вызовами функций, а второе выражение loop_condition – выражением отношения или логическим выражением [3.1]. Любую из трех частей можно опустить, но точки с запятыми должны остаться на своих местах. Если опустить init_expression или loop_expression, то соответствующие операции не будут выполняться. Если же опустить проверку условия loop_condition, то по умолчанию считается, что условие продолжения цикла всегда истинно, и тогда цикл станет бесконечным (произойдет зацикливание).

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

    for (init_expression; loop_condition; loop_expression)
    {
    program1 statement1;
    program2 statement2;
    program3 statement3;
    ...
    }

    В представленном случае тело цикла находится в фигурных скобках.

    Конструкция цикла, реализованная оператором for, может быть выполнена также и оператором while следующим образом [3.1]:

    init_expression;
    while (loop_condition)
    {
    program statement;
    loop_expression;
    }

    Исключением является применение операции continue.

    Операторы отношения перечислены в табл. 3.1.

    Операторы отношения языка программирования С
    № п/п Оператор Значение
    1) == Равно
    2) != Не равно
    3) < Меньше
    4) <= Меньше или равно
    5) > Больше
    6) >= больше или равно

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

    3.3. Оператор do–while

    Рассмотренные операторы цикла while и for производят проверку условия выполнения цикла до начала выполнения тела цикла [3.1]. Поэтому тело цикла может ни разу не выполниться, если с самого начала результатом расчета условия выполнения цикла будет значение FALSE (ложь). В случае необходимости производить проверку условия выполнения цикла после тела цикла (т.е. когда выполняется хотя бы одно предписанное действие в теле цикла) прибегают к циклу do–while.

    Оператор цикла do–while имеет следующий формат записи [3.2]:

    do
    program statement;
    while (loop_condition);

    Выполнение цикла do–while происходит следующим образом: сначала выполняется утверждение program statement, затем производится проверка условия выполнения цикла loop_condition с помощью оператора while. Если результатом проверки будет значение TRUE (истина), то выполнение цикла продолжится, и утверждение program statement всякий раз будет выполняться вновь. Повторение цикла будет продолжаться до тех пор, пока в результате проверки условия выполнения цикла loop_condition будет получаться значение TRUE. Когда в результате проверки условия будет вычислено значение FALSE (ложь), то выполнение цикла прекратится и произойдет переход к утверждению (следующему фрагменту программы), непосредственно следующему за циклом [3.2].

    Таким образом, цикл do–while гарантированно выполнится хотя бы один раз.

    В случае выполнения нескольких утверждений используются фигурные скобки для выделения тела цикла:

    do {
    program1 statement1;
    program2 statement2;
    program3 statement3;
    ... } while (loop_condition);

    Оператор цикла while называется оператором цикла с предусловием, оператор цикла for называется оператором цикла с параметром, оператор цикла do–while называется оператором цикла c постусловием.

    Практическая часть

    Рассмотрим примеры программ с операторами циклов while, for и do–while.

    Пример 1. Напишите программу вывода на экран пользователя целых положительных чисел с помощью оператора while. Начальное и последнее число должно задаваться пользователем с клавиатуры.

    Программный код решения примера:

    #include <stdio.h>
    #include <conio.h>
    
    int main(void)
     {
    int i, j = 0, n;
    printf("\n\t Enter the primary natural number: ");
    scanf_s("%d", i);
    printf("\t Enter the last natural number: ");
    scanf_s("%d", n);
    
    printf("\n\t The numbers are:");
    while (i <= n) {
    printf("\n\t %3d", i);
    ++i;
    ++j; 
    }
    printf("\n\t Total numbers: %d\n", j);
    	
    printf("\n Press any key: ");
    	_getch();
    	return 0;
     }
    (рис 3.1) Результат выполнения программы с вводом целых чисел

    Возможный результат выполнения программы показан на рис 3.1.

    В программе использована функция scanf_s(), принятая в MS Visual Studio. В программе применено инкрементирование переменных, принятое в языке С, а именно ++i или ++j означает, что переменные увеличиваются на единицу. При этом знаки "++" могут располагаться перед именем переменной или после. Отличие в том, что ++i – это значение переменной после увеличения, а i++ – сначала переменная имеет заданное значение, а потом происходит ее увеличение. Для переменных цикла обе формы равнозначны.

    Условием цикла является то, что пока переменная i меньше или равна переменной n (предполагается, что n больше начального значения i ), то будут выполняться действия (печать и увеличение переменной j ), заложенные в теле цикла. Расчет выражения, заключенного в круглые скобки оператора, предназначен для проверки нестрогого неравенства переменной i по отношению к переменной n. Если это неравенство выполняется, то в теле цикла происходят печать и увеличение (инкрементирование) переменных i, j.

    Задание 1

  • Предусмотрите ввод только отрицательных чисел.
  • Предусмотрите ввод только неотрицательных чисел.
  • Предусмотрите вывод чисел и их порядковые номера (т.е. в два столбца).
  • Предусмотрите вывод чисел на консоль в виде строки.
  • Предусмотрите ввод и вывод только вещественных чисел.
  • С учетом предыдущего пункта предусмотрите вывод чисел и их порядковые номера (т.е. в два столбца).
  • Рассмотреть варианты форм инкрементирования. Выполните вывод на консоль.
  • Пример 2. Напишите программу посимвольного ввода предложения "Hello, world" и подсчитать число символов в нем (включая запятую и пробел).

    Программный код решения примера:

    #include <stdio.h>
    #include <conio.h>
    
    int main(void)
    {
    	int c, i = 0;
    
    printf("\n Enter symbol-by-symbol the offer \"Hello, world\",\n  press twice Ctrl+Z and press Enter:\n");
    printf("\t");
    
    while ((c = getchar()) != EOF)
    {
    printf("\t");
    c = getchar();
    ++i;
    }
    
    printf("\n\t The number of characters: %d\n", i);
    	
         printf("\n Press any key: ");
    	_getch();
    	return 0;
    }

    В программе ввод символьных данных должен завершиться комбинацией клавиш Ctrl+Z, что будет соответствовать окончанию ввода (файла), т.е. EOF. Оператор цикла while будет выполняться до тех пор, пока не встретится так называемый конец файла EOF. В предложении \"Hello, world\" два обратных слэша включены для вывода на консоль двойных кавычек.

    Функции printf("\t") осуществляют табуляцию вводимых символов. Подсчет числа вводимых символов выполняется с помощью переменной цикла (счетчика) i, которая инкрементируется в теле цикла.

    Заголовочный файл #include <conio.h> служит для поддержания консольного ввода-вывода для функции _getch(). Без него при компиляции программы могут выводиться предупреждения, хотя программа с предупреждениями работает.

    Результат выполнения программы показан на рис 3.2.

    (рис 3.2) Выполнение программы посимвольного ввода данных

    Задание 2

  • В программу введите комментарии с помощью символов // и /*...*/.
  • В качестве вводимых символов используйте буквы своей фамилии (буквами латинского алфавита). В отчет вставьте полученный результат.
  • В качестве вводимых символов использовать свою фамилию и имя. В отчет вставьте полученный результат.
  • Сделайте вывод своей фамилии и имени по главной диагонали дисплея.
  • В качестве символов введите числа от 1 до (2+Х), где Х – номер компьютера, за которым выполняется лабораторная работа. В отчет вставьте полученный результат.
  • Выполните дублирование символов с помощью функции putchar(), которая отображает символы на экране пользователя.
  • Примечание. Прототип функции putchar() имеет следующий вид:

    #include <stdio.h>
    int putchar (int ch);

    Пример 3. Напишите программу табличного вывода строчных букв латинского алфавита и их десятичных кодов с помощью оператора цикла for.

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

    Программный код решения примера:

    #include <stdio.h>
    #include <conio.h>
    int main(void){
    	int j = 1;
    	char a = 'a';
    	
    	printf("\n  Table code characters:\n");
    for ( ; a <= 'z'; ++a)
    	printf("\n %4d) %2c: code%4d", j++, a, a);
    
    	printf("\n\n Press any key: ");
    	_getch();
    	return 0;
    }

    Результат выполнения программы показан на рис 3.3.

    (рис 3.3) Таблица десятичных кодов букв латинского алфавита

    Форматированный вывод данных предусматривает выравнивание по правому краю, для чего предусматриваются числовые спецификаторы типа %4d и %2c для целых чисел и символов в функции printf().

    Задание 3

  • Примените префиксную форму инкрементирования переменной j.
  • Инкрементирование переменной j создайте отдельно в теле цикла.
  • Инициализацию переменной j начните с нуля. Результат выполнения программы должен быть тот же самый, что и в приведенной программе.
  • Напишите программу для вывода кодов букв из заданного диапазона на усмотрение пользователя, например, от 'j' до 'w'.
  • В цикле for заполните все поля.
  • Напишите программу для вывода кодов букв латинского алфавита прописных и строчных букв в одной таблице.
  • Выведите буквы своей фамилии и коды этих букв.
  • Напишите программу расчета значений функции распределения потока Эрланга 4-го порядка с параметром $$\lambda$$ = 2.3 на отрезке времени от 0 до 5 (условных единиц) с шагом 0.2:

    $$F_k(t)=1-\sum\limits_{j=0}^{k}\frac{(\lambda t )^j}{j!}{e}^{-\lambda t}.$$

    Программный код решения примера:

    #include <stdio.h>
    #include <conio.h>
    #include <math.h>
    
    int main(void)
     {
    	int j, f, k = 4;
    	double F, Lt, s, t = 0.0, Tend = 5.0;
    	float L = 2.3F;
    		
    printf("\n Erlang function of order %d, Lambda = %1.2f:\n\n", k, L);
    		
    for ( ; t <= Tend; t += 0.2) {
    s = 0.0; f = 1; Lt = 1.0;
    for (j = 1; j <= k; ++j) {
    f *= j;
    Lt *= (L*t);
    s += (Lt/f)*exp(-L*t);
    }
    F = 1 - exp(-L*t) - s;
    printf("\t %lg\n", F);
    }
    	printf("\n\n Press any key: ");
    	_getch();
    	return 0;
    }

    В программе использованы вложенные циклы for. Применены специфические условия изменения переменных (но характерных для языка С ):

    t += 0.2;      /* t  =  t + 0.2; */
         f *= j;        /* f  =  f * j; */
        Lt *= (L*t);    /* Lt  =  Lt * (L*t); */

    Вычисление факториала выполнено с помощью произведения и выделения отдельного слагаемого суммы, когда рассчитывается 0!

    В программе также предусмотрено накопление суммы для каждого шага времени t. Для расчета экспоненты в заголовок программы включена библиотека математических функций #include <math.h>.

    Результат выполнения программы показан на рис 3.4.

    (рис 3.4) Расчет функции распределения Эрланга 4-го порядка

    Задание 4

  • В заголовке внешнего цикла for добавьте первое поле и устраните третье поле.
  • Предусмотрите вывод количества значений рассчитанной функции Эрланга.
  • Предусмотрите ввод параметров программы, а именно: порядок потока Эрланга k, параметр $$\lambda$$, конечную величину временного интервала, шаг по времени.
  • Пример 5. Вычислите с точностью до "машинного нуля" значение суммы числового ряда:

    $$\frac 1 {1\cdot 2\cdot 3}+ \frac 1 {2\cdot 3\cdot 4}+\frac 1 {3\cdot 4\cdot 5}+\frac 1 {4\cdot 5\cdot 6}+\cdots$$

    Программный код решения примера:

    #include <stdio.h>
    #include <conio.h>
    
    int main(void)
     {
       double denom;
       double sum1 = 0.0, sum2 = 0.0;
       int k = 1;
       denom = k * (k + 1) * (k + 2); // знаменатель ряда
    
    	do {
    	sum1 = sum2;
    	sum2 += 1.0 / denom;
    	denom = denom / k * (k + 3);
    	++k;
    	} while (sum1 < sum2);
    
    printf("\n\t The amount of numerical series: %lg\n", sum2);
    	
    	printf("\n Press any key: ");
    	_getch();
    	return 0;
    }

    В приведенной программе сумма вычисляется как значение переменной sum2. Ее предыдущее значение сохраняется в переменной sum1. Так как приближенное значение с добавлением неотрицательных слагаемых не уменьшается, условием продолжения цикла служит отношение sum1 < sum2 (поскольку растет знаменатель denom ). Когда при добавлении очередного слагаемого значение суммы остается неизменным (за счет конечной разрядной сетки для представления вещественных чисел), нарушается условие sum1 < sum2 и цикл прекращается. Таким образом, конечность разрядной сетки представления вещественных чисел в компьютере определяет собой "машинный нуль".

    Инициализация знаменателя сделана до начала цикла. Форматный вывод результата выполнен с помощью спецификатора символа "l".

    Результат выполнения программы показан на рис 3.5.

    (рис 3.5) Результат подсчета суммы бесконечного ряда

    Задание 5

  • Подсчитайте число итераций цикла для подсчета суммы ряда.
  • Напишите программу с нулевой инициализацией переменной k.
  • Напишите условие "загрубения" результата подсчета суммы ряда.
  • В программе примените тип float вместо типа double. Проанализируйте результат.
  • Вместо оператора цикла do–while примените иной оператор цикла.
  • Пример 6. Произведите реверс цифр заданного целого числа, вводимого с клавиатуры пользователем.

    Задача заключается в том, чтобы, например, число 123 переписать как 321.

    Программный код решения примера:

    #include <stdio.h>
    #include <conio.h>
    
    int main(void)
     {
    	long int x, r;
    
    	printf("\n Enter an integer: ");
    	scanf_s("%ld", x);
    
    	printf("\n Reverse-digit number %ld:\n\n\t", x);
    
    	do {
    	r = x % 10;
    	printf(" %ld", r);
    	x = x / 10;
    	} while ( x != 0);
    
    	printf("\n\n Press any key: ");
    	_getch();
    	return 0;
    }

    В программе применена операция арифметическая операция деления по модулю, которая имеет символ процента, т.е. "%". Любой остаток, получающийся в результате деления целых чисел, будет отброшен [3.2]. В шкале старшинства оператор деления по модулю имеет приоритет, равный приоритету операторов умножения и деления. Переменные, используемые в программе, объявлены как длинные числа, поэтому применен тип long int (или long ). В некоторых компиляторах имеются отличия между типами int и long int в смысле максимально поддерживаемого значения числа.

    Результат выполнения программы показан на рис 3.6.

    (рис 3.6) Результат программы по реверсу числа

    Задание 6

  • Предусмотрите подсчет итераций заданного цикла.
  • Напишите программу по реверсу числа с оператором цикла while. Протестируйте обе программы, в том числе по вводу числа 0.
  • Определите максимальное число вида 123...987..., для которого еще можно применить тип long int.
  • Пример 7. На основе только оператора цикла for напишите программу по выводу "горки" заглавных букв, симметрично убывающих к букве, введенной пользователем. Также на основе оператора цикла for предусмотрите защиту от неправильного ввода.

    Программный код решения примера:

    #include <stdio.h>
    #include <conio.h>
    
    int main (void) {
    	int p = 0;
         char ch = 'A'; 
         char i, j, k, ch2, kk, chA;
         chA = ch;
    
    printf("\n   Enter a capital letter between \"A\" and \"S\": ");
    scanf_s("%c", ch2, sizeof(char));
    
    for(chA -= 1; chA >= ch2; chA-- )
     {
    	printf("\n   Error! Press any key: ");
    	_getch();
    	return -1;
     }
    
    for (kk = 'S'+1; kk  <= ch2; kk++) 
    {
    printf("\n   Error! Press any key: ");
    	_getch();
         return -1;
    }
    
    k = ch2;
    for ( kk = ch; kk <=  k; kk++)
     {
    		printf("\n ");
    
    for (ch2 = ch; ch2 <= k-p ; ch2++) 		
    			printf("  ");	
    
    for (j = ch; j <= kk ; j++)  
    		printf(" %c", j);	
    	for (i = kk; i > ch; i-- )
    			printf(" %c", i-1);
    	p++;
    		
    }
        printf("\n\n Press any key: ");
    	_getch();
    	return 0;
    }

    Пример выполнения программы показан на рис 3.7.

    (рис 3.7) Пример горки букв

    Задание 7

  • Напишите программу на основе только оператора цикла for по выводу перевернутой горки букв, а также "левой" и "правой" горки.
  • Напишите программу на основе только оператора цикла for по выводу "ромба" букв, относительно введенной буквы.
  • Напишите программу по выводу горки букв только на основе оператора цикла while.
  • Контрольные вопросы

  • Как организуются составные операторы циклов в языке С?
  • Как организуются вложенные циклы в языке С?
  • В каких случаях может произойти зацикливание при использовании оператора цикла с предусловием?
  • В каких случаях может произойти зацикливание при использовании оператора цикла с постусловием?
  • Сколько условий требуется для работы оператора цикла с параметром?
  • Чем отличаются префиксное и постфиксное инкрементирование и декрементирование?
  • Какое различие в операторах цикла между префиксным и постфиксным инкрементированием?
  • Сколько операторов отношения в языке С? Перечислите их.
  • Как реализуется взаимозаменяемость операторов цикла while и for?
  • В чем сходство и различие между циклами с предусловием и с постусловием?
  • Вернуться к учебному плану