Урок 4. Циклы в языке C

Особенности языка С. Учебное пособие

Инкремент и декремент

Прежде, чем изучать циклы, следует познакомиться с часто используемым в языке C способом увеличения/уменьшения значений переменных на единицу. Конечно, в C работают такие формы изменения значений как, например, a += 1 или a -= 1. Однако чаще используют операции инкрементирования (оператор инкремента "++") и декрементирования (оператор декремента "--"): i++ или ++i, i-- или --i. В результате этих операций переменные увеличиваются или уменьшаются на единицу.

Запомните, когда вы видите выражения типа ++i или i++, то в результате их выполнения значение i меняется. Не надо делать вот так: i = ++i. Это совершенно лишнее.

Когда знак инкремента или декремента стоит перед переменной, то перед нами префиксная форма операции (++i, --i), а когда после переменной, то постфиксная форма (i++, i--). Когда эти выражения не участвуют в построении более сложных выражений, то между префиксной и постфиксной формами никакой разницы нет: что i++, что ++i — без разницы, в результате мы получим значение i на единицу больше. Но когда эти выражения участвуют в построении более сложных, то разница между префиксной и постфиксной формами появляется и заключается в следующем: переменная над которой производится операция инкрементирования или декрементирования в постфиксной форме сначала используется в сложном выражении как есть, и только потом увеличивается на единицу; если мы имеем дело с префиксной формой, то переменная сначала изменяется, а затем используется. Например, код:

  int a, b, c, d;
  a=b=c=d=0; // выражение означает, что всем переменным присваивается 0
  printf("a=%d, b=%d, c=%d, d=%d\n", a, b, c, d);
  c = ++a;
  d = b++;
  printf("a=%d, b=%d, c=%d, d=%d\n", a, b, c, d);

, выведет на экране:

a=0, b=0, c=0, d=0 
a=1, b=1, c=1, d=0 

Объясняется такой результат так:

  • значение переменной a было увеличено на единицу, после чего это значение было присвоено переменной c;
  • значение переменной b было сначала присвоено переменной d и только потом увеличено на единицу.

Еще один пример:

  int x, y;
  x = y = 0;
  printf("%d\n", x++ > 0);
  printf("%d\n", ++y > 0);

На экране будет выведено:

0
1

Это результат логических выражений, где 0 означает ложь, а 1 — истину. В данном случае, когда x сравнивается с нулем, то его значение еще не увеличено, а когда сравнивается у, то его значение уже больше нуля.

Применять операторы инкремента и декремента можно также к переменным вещественного типа.

Задание
Придумайте более сложные, чем представленные выше, выражения с использованием операторов инкремента и декремента. Проверьте и объясните результат их выполнения.

while

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

Задание

  1. Присвойте переменной star значение 0. Пока значение star не достигнет 55 выводите на экран в строку по одной звездочке (*).
  2. С помощью цикла while запрограммируйте вывод на экран цифровых кодов и значений таблицы символов ASCII от 31 до 127 включительно. При этом после каждого десятого символа осуществляйте переход на новую строку. (Подсказка: чтобы переходить на новую строку, в цикле while надо использовать инструкцию if, в условии которой остаток1 от деления на 10 сравнивается с нулем.)
    Вывод таблицы символов на языке программирования C
  3. Используя внешний и вложенный циклы while организуйте вывод таблицы умножения на экран.
    Вывод на языке программирования C таблицы умножения

1 Операция нахождения остатка от деления в языке C обозначается знаком процента (%).

do-while

Цикл do-while отличается от while лишь тем, что его тело будет выполнено хотя бы один раз независимо от условия выполнения цикла. Синтаксис цикла do-while можно описать так (фигурные скобки можно опустить, если законченное выражение только одно):

do {
    выражение1;;
} while (логич_выражение);

Этот цикл называют циклом с постусловием. Его используют намного реже обычного while. В принципе почти всегда можно обойтись без него, но в определенных ситуациях его использование упрощает код. Допустим требуется вывести на экран отдельные цифры числа. Любое число состоит хотя бы из одной цифры, даже число 0. Можно решить эту задачу с использованием цикла while:

  while (a > 0) {
    printf("%d\n", a % 10);
    a = a / 10;
  }

Но в этом случае, если a равно 0, то цикл не выполнится ни разу. Пришлось бы перед циклом использовать инструкцию if, в которой сравнивать переменную с 0. Использование же цикла do-while решает эту проблему, т.к. его тело один раз выполнится даже при нулевом значении переменной:

  do {
    printf("%d\n", a % 10);
    a = a / 10;
  } while (a > 0);

Задание
Придумайте и напишите любую программу, в которой бы использовался цикл do-while.

for

Представим синтаксис заголовка цикла for языка программирования C так:
for (часть1; часть2; часть3)

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

Вот так будет выглядеть программный код, выводящий таблицу символов на экран, в котором используется цикл for:

  unsigned char a;
  for (a = 31; a < 128; a++) {
    if (a % 10 == 0)
      printf("\n");
    printf("%4d-%c", a, a);
  }
  printf("\n");

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

break и continue

Оператор break позволяет прервать выполнение цикла, а continue — прервать текущую итерацию (проход) цикла. Почти всегда можно обойтись без этих операторов, но иногда их использование позволяет упростить программный код и сделать его более понятным.

Рассмотрим пару примеров. Допустим, требуется проверить массив на наличие в нем хотя бы одного элемента со значением 0. Как только ноль будет обнаружен проверять оставшуюся часть массива уже нет смысла. Поэтому, чтобы не выполнять лишних итераций, используется оператор break.

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

  #define N 10
  int arr[N] = {6, 5, -4, 3, -7, 2, 7, 0, 3, 9};
  int new_arr[N], i, j;
 
  for (i=0; i<N; i++) {
    printf("%d  ", i); // просто проверка
    if (arr[i] == 0) {
      printf("Stop. Array contains zero\n");
      break;
    }
  }
  printf("\n");
 
  for(i=0, j=0; i<N; i++) {
    if (arr[i] <= 0)
      continue;
    new_arr[j] = arr[i];
    printf("%d  ", new_arr[j]); // проверка
    j++;
  }  
  printf("\n");

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

Задание
Придумайте пример, в котором уместно было бы использовать оператор break или continue.