Операторы цикла в языке Си

Язык Си / Операторы цикла в языке Си

 

Рассмотрим третью алгоритмическую структуру — цикл.
Циклом называется блок кода, который для решения задачи требуется повторить несколько раз.

Каждый цикл состоит из

  • блока проверки условия повторения цикла
  • тела цикла

 
Цикл выполняется до тех пор, пока блок проверки условия возвращает истинное значение.
Тело цикла содержит последовательность операций, которая выполняется в случае истинного условия повторения цикла. После выполнения последней операции тела цикла снова выполняется операция проверки условия повторения цикла. Если это условие не выполняется, то будет выполнена операция, стоящая непосредственно после цикла в коде программы.

В языке Си следующие виды циклов:

  • while — цикл с предусловием;
  • do…while — цикл с постусловием;
  • for — параметрический цикл (цикл с заданным числом повторений).

 

Цикл с предусловием while

Общая форма записи

 
 
 
 
while (Условие)
{
  БлокОпераций;
}

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

Пример на Си: Посчитать сумму чисел от 1 до введенного k
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
int main() {
  int k;  // объявляем целую переменную key
  int i = 1;
  int sum = 0; // начальное значение суммы равно 0
  printf("k = ");
  scanf("%d", &k);   // вводим значение переменной k
  while (i <= k)     // пока i меньше или равно k
  {
    sum = sum + i; // добавляем значение i к сумме
    i++;           // увеличиваем i на 1
  }
  printf("sum = %d\n", sum); // вывод значения суммы
  getchar(); getchar();
  return 0;
}

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

Пример бесконечного цикла
1
2
3
4
while (1)
{
  БлокОпераций;
}


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

Например, если в приведенном выше коде программы ввести k=-1, то получим результат
Цикл while может не выполниться ни разу

Цикл с постусловием do...while

Общая форма записи

 
 
 
do {
  БлокОпераций;
while (Условие);

Цикл do...while — это цикл с постусловием, где истинность выражения, проверяющего Условие проверяется после выполнения Блока Операций, заключенного в фигурные скобки. Тело цикла выполняется до тех пор, пока выражение, проверяющее Условие, не станет ложным, то есть тело цикла с постусловием выполнится хотя бы один раз.

Использовать цикл do...while лучше в тех случаях, когда должна быть выполнена хотя бы одна итерация, либо когда инициализация объектов, участвующих в проверке условия, происходит внутри тела цикла.

Пример на Си. Проверка, что пользователь ввел число от 0 до 10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
#include <stdlib.h> // для использования функции system()
int main() {
  int num;             // объявляем целую переменную для числа
  system("chcp 1251"); // переходим на русский язык в консоли
  system("cls");       // очищаем экран
  do {
    printf("Введите число от 0 до 10: "); // приглашение пользователю
    scanf("%d", &num); // ввод числа
  } while ((num < 0) || (num > 10)); // повторяем цикл пока num<0 или num>10
  printf("Вы ввели число %d", num); // выводим введенное значение num - от 0 до 10
  getchar(); getchar();
  return 0;
}

Результат выполнения:
Цикл do...while

Параметрический цикл for

Общая форма записи

 
 
 
 
for (Инициализация; Условие; Модификация)
{
  БлокОпераций;
}


for — параметрический цикл (цикл с фиксированным числом повторений). Для организации такого цикла необходимо осуществить три операции:

  • Инициализация - присваивание параметру цикла начального значения;
  • Условие - проверка условия повторения цикла, чаще всего - сравнение величины параметра с некоторым граничным значением;
  • Модификация - изменение значения параметра для следующего прохождения тела цикла.

 
Эти три операции записываются в скобках и разделяются точкой с запятой ;;. Как правило, параметром цикла является целочисленная переменная.
Инициализация параметра осуществляется только один раз — когда цикл for начинает выполняться.
Проверка Условия повторения цикла осуществляется перед каждым возможным выполнением тела цикла. Когда выражение, проверяющее Условие становится ложным (равным нулю), цикл завершается. Модификация параметра осуществляется в конце каждого выполнения тела цикла. Параметр может как увеличиваться, так и уменьшаться.

Пример на Си: Посчитать сумму чисел от 1 до введенного k

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
int main() {
  int k;  // объявляем целую переменную key
  int sum = 0; // начальное значение суммы равно 0
  printf("k = ");
  scanf("%d", &k);   // вводим значение переменной k
  for(int i=1; i<=k; i++) // цикл для переменной i от 1 до k с шагом 1
  {
    sum = sum + i; // добавляем значение i к сумме
  }
  printf("sum = %d\n", sum); // вывод значения суммы
  getchar(); getchar();
  return 0;
}

Результат выполнения
Цикл while
В записи цикла for можно опустить одно или несколько выражений, но нельзя опускать точку с запятой, разделяющие три составляющие цикла.
Код предыдущего примера можно представить в виде

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
int main() {
  int k;  // объявляем целую переменную key
  int sum = 0; // начальное значение суммы равно 0
  printf("k = ");
  scanf("%d", &k);   // вводим значение переменной k
  int i=1;
  for(; i<=k; i++) // цикл для переменной i от 1 до k с шагом 1
  {
    sum = sum + i; // добавляем значение i к сумме
  }
  printf("sum = %d\n", sum); // вывод значения суммы
  getchar(); getchar();
  return 0;
}


Параметры, находящиеся в выражениях в заголовке цикла можно изменить при выполнении операции в теле цикла, например
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
int main() {
  int k;  // объявляем целую переменную key
  int sum = 0; // начальное значение суммы равно 0
  printf("k = ");
  scanf("%d", &k);   // вводим значение переменной k
  for(int i=1; i<=k; ) // цикл для переменной i от 1 до k с шагом 1
  {
    sum = sum + i; // добавляем значение i к сумме
    i++;           // добавляем 1 к значению i

  }
  printf("sum = %d\n", sum); // вывод значения суммы
  getchar(); getchar();
  return 0;
}


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

Пример на Си:
1
2
3
4
5
6
7
8
9
10
11
12
13
#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
int main() {
  int k;  // объявляем целую переменную key
  printf("k = ");
  scanf("%d", &k);   // вводим значение переменной k
  for(int i=1, j=2; i<=k; i++, j+=2) // цикл для переменных
  {                                  // (i от 1 до k с шагом 1) и (j от 2 с шагом 2)
    printf("i = %d   j = %d\n", i, j); // выводим значения i и j
  }
  getchar(); getchar();
  return 0;
}

Результат выполнения
Цикл for

Вложенные циклы

В Си допускаются вложенные циклы, то есть когда один цикл находится внутри другого:

 
 
 
 
 
 
 
 
for (i = 0; i<n; i++)  // внешний цикл - Цикл1
{     
  for (j = 0; j<n; j++)   // вложенный цикл - Цикл2
  {
    ;        // блок операций Цикла2
  }
  // блок операций Цикла1;
}


Пример: Вывести числа от 0 до 99, по 10 в каждой строке
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
int main() {
  for(int i=0; i<10; i++) // цикл для десятков
  {                                  
    for (int j = 0; j < 10; j++) // цикл для единиц
    {
      printf("%2d ", i * 10 + j); // выводим вычисленное число (2 знакоместа) и пробел
    }
    printf("\n"); // во внешнем цикле переводим строку
  }
  getchar(); // scanf() не использовался,
  return 0;  // поэтому консоль можно удержать одним вызовом getchar()
}

Результат выполнения
Вложенные циклы: вывод чисел от 0 до 99

Рекомендации по выбору цикла

При выборе цикла необходимо оценить необходимость проверки условия при входе в цикл или по завершении прохождения цикла.
Цикл с постусловием удобно применять в случаях, когда для проверки условия требуется вычислить значение выражения, которое затем будет размещено в теле цикла (см. выше пример ввода числа от 0 до 10).
Цикл c предусловием используется в случае если все переменные, участвующие в выражении, проверяющем условие, проинициализированы заранее, но точное число повторений цикла неизвестно или предполагается сложная модификация переменных, участвующих в формировании условия повторения цикла.
Если цикл ориентирован на работу с параметром, для которого заранее известно число повторений и шаг изменения, то более предпочтительным является параметрический цикл. Очень удобно использовать параметрический цикл при работе с массивами для перебора элементов.

Операторы прерывания и продолжения цикла break и continue

В теле любого цикла можно использовать операторы прерывания цикла - break и продолжения цикла - continue.

Оператор break позволяет выйти из цикла, не завершая его.
Оператор continue позволяет пропустить часть операторов тела цикла и начать новую итерацию.

Пример на Си: Вывести числа от 0 до 99 ниже главной диагонали

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
int main() {
  for(int i=0; i<10; i++) // цикл для десятков
  {                                  
    for (int j = 0; j < 10; j++) // цикл для единиц
    {
      if (j > i) // если число единиц больше числа десятков в числе
        break// выходим из вложенного цикла и переходим к новой строке
      printf("%2d ", i * 10 + j); // выводим вычисленное число (2 знакоместа) и пробел
    }
    printf("\n"); // во внешнем цикле переводим строку
  }
  getchar(); // scanf() не использовался,
  return 0;  // поэтому консоль можно удержать одним вызовом getchar()
}

Результат выполнения
Оператор break

Пример на Си: Вывести числа от 0 до 99 исключая числа, оканчивающиеся на 5 или 8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
int main() {
  for(int i=0; i<10; i++) // цикл для десятков
  {                                  
    for (int j = 0; j < 10; j++) // цикл для единиц
    {
      if ((j == 5) || (j == 8)) // если число единиц в числе равно 5 или 8,
        continue;             // переходим к следующей итерации цикла
      printf("%2d ", i * 10 + j); // выводим вычисленное число (2 знакоместа) и пробел
    }
    printf("\n"); // во внешнем цикле переводим строку
  }
  getchar(); // scanf() не использовался,
  return 0;  // поэтому консоль можно удержать одним вызовом getchar()
}

Результат выполнения
Оператор continue

При вложенных циклах действия операторов break и continue распространяется только на самую внутреннюю структуру, в которой они содержатся.

Оператор безусловного перехода goto

Общая форма записи

 
 
 
goto Метка;
. . .
Метка : Операция;


Выполнение оператора goto вызывает передачу управления в программе операции, помеченной Меткой. По сути Метка является идентификатором адреса операции, которой должно быть передано управление. Для отделения Метки от Операции используется двоеточие - :.
Метка может располагаться в программе как до оператора goto, так и после него. Имена Меток образуются по тем же правилам, что и имена переменных.

Пример на Си: Вывести все целые числа от 5 до 0.
1
2
3
4
5
6
7
8
9
10
11
12
#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include <stdio.h>
int main() {
  int k = 5;
M1: if (k < 0) // если k<0,
    goto M2;   // переходим на метку M2 (выходим из программы)
  printf("%d ", k); // выводим значение k
  k--;              // уменьшаем k на 1
  goto M1;          // переходим на метку M1 (повторяем операции выше)
M2: getchar();
  return 0;
}

Результат выполнения
Оператор goto

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


Назад: Язык Си

Комментариев к записи: 26

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include <locale.h>

    int main()
    {
        setlocale(LC_ALL, "rus");
        int x, n;
        printf("Введите ваш x: ");
        scanf("%d", &x);
        printf("Введите ваш n: ");
        scanf("%d", &n);
        double S;

        for(int k=1; ((k<=n)); k++)
        {
            if((2*(k-2)*pow(x,3*k+1))!=0)
                {
                    S += (pow(-3,3*k+1))/2*(k-2)*pow(x,3*k+1);
                }
              for(int m=1; ((m<=k+2)&&(m!=2)); m++)
            {
                if((m-4)!=0)
                {
                    S *= (pow(m,3)-8)/(m-4);
                }
            }
        }
         printf("S = %.2lf" , S);
        return 0;
    }
    Не правильно считает произведение чисел и не понимаю что не так-помогите пожалуйста

    • Елена Вставская
      Всё ли в порядке с типами данных? S имеет тип double, а все переменные, участвующие в вычислениях, целые.

  • Как вывести кол-во компьютеров у которых больше 10Гб оперативной памяти?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    #include<stdio.h>
    #include<stdlib.h>
    const N = 4;
    struct komp
    {
        char nazvanie[30];
        int chastota_cp;
        int operativa;
        char nalichie_dvd[30];
        int cost;
    };

    main()
    {

        setlocale(0, "");
        int count = 0;
        int i;

        struct komp k[4] =
        {
            "Komp_1", 3200, 16, "Есть", 35000,
            "Komp_2", 4200, 8, "Нет", 40000,
            "Komp_3", 3800, 12, "Нет", 39000,
            "Komp_4",3600, 4,"Есть",30000
        };

            if(k[0].operativa>10)
                {
                printf("\nКомпьютер у которого > 10Гб: \n\nНазвание: %s \nЧастота ЦП: %d \nКол-во оперативной памяти: %d \nНаличие DVD: %s \nСтоимость: %d\n", k[0].nazvanie,k[0].chastota_cp,k[0].operativa,k[0].nalichie_dvd,k[0].cost);
                }
            else
            {
                printf("\n\n");
            }

            if(k[1].operativa>10)
                {
                printf("\nКомпьютер у которого > 10Гб: \n\nНазвание: %s \nЧастота ЦП: %d \nКол-во оперативной памяти: %d \nНаличие DVD: %s \nСтоимость: %d\n", k[1].nazvanie,k[1].chastota_cp,k[1].operativa,k[1].nalichie_dvd,k[1].cost);
                }
            else
            {
                printf("\n\n");
            }

            if(k[2].operativa>10)
                {
                printf("\nКомпьютер у которого > 10Гб: \n\nНазвание: %s \nЧастота ЦП: %d \nКол-во оперативной памяти: %d \nНаличие DVD: %s \nСтоимость: %d\n", k[2].nazvanie,k[2].chastota_cp,k[2].operativa,k[2].nalichie_dvd,k[2].cost);
                }
            else
            {
                printf("\n\n");
            }

            if(k[3].operativa>10)
                {
                printf("\nКомпьютер у которого > 10Гб: \n\nНазвание: %s \nЧастота ЦП: %d \nКол-во оперативной памяти: %d \nНаличие DVD: %s \nСтоимость: %d\n", k[3].nazvanie,k[3].chastota_cp,k[3].operativa,k[3].nalichie_dvd,k[3].cost);
                }
            else
            {
                printf("\n\n");
            }


        return 0;
    }

    • Елена Вставская
      Наверное, удобнее в цикле
      1
      2
      3
      4
      5
      for(int i=0;i<4;i++)
      {
      if(k[i].operativa>10)
        {...}
      }

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #include <stdio.h>
    int evensCount(int number);
    int main()
    {
        int res = evensCount (45678);
      printf("res = %d",res);

        return 0;
    }
    int evensCount(int number)
    {
      int rem = 0,count = 0;
        do{
        rem = number % 10;
        if (rem / 2 == 0);
        count++;
        // number = number / 10;
        }while(number != 0);
        return count;
    }
    не могу понять почему не выводит четные числа

    • Елена Вставская
      Вы не выводите четные числа, а считаете количество чётных цифр в числе. Если, конечно, раскомментируете строчку n=n/10; Иначе программа вообще зависнет.

  • Здравствуйте. Обращаюсь к собравшимся за помощью по следующему вопросу. Написал код для нахождения ряда
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    #include <stdio.h>
    #include <stdlib.h>
    #include <locale.h>
    #include <math.h>
      double fct ( double n)
    {
        if(n>=1)
        {
            return n*fct(n-1);
        }
        else
        {
            return 1;
        }
    }
    int main()
    {
        setlocale(0, "Russian");
        double x, e, cos_x, a, sum, i, k, b;
        printf("Введите переменную x: \n");
        scanf("%lf", &x);
        printf("Введите значение погрешности e: \n");
        scanf("%lf", &e);
        cos_x = cos(x);
        printf("Значение, к которому стремится ряд = %lf \n", cos_x);
        for(sum=0, i=0; (sum<cos_x - e)||(sum>cos_x + e); i++)
        {
            a=pow(-1,i)*pow(x,2*i)/fct(2*i);
            sum=sum+a;
        }
        printf("Конечный член ряда = %lf \n", a);
        printf("Сумма на сравнение = %lf \n", sum);
        printf("Количество итераций = %lf \n", i);
        return(0);
    }
    В онлайн компиляторе он работает, только если я произвожу ввод на английском шрифте. А в компиляторе кодеблок не работает вовсе. Даже ошибок не выдает. Просто неверно считает. Версия 10.05 При этом было установлено, что если я заменяю условие или на какое - либо другое в условии цикла, то программа работает как надо. В чем может быть дело и что делать, чтобы программа работала в кодеблоке? Заранее спасибо

    • Елена Вставская
      В переменной sum до первого вычисления a находится мусор. Он может быть разный в онлайн компиляторе и в codeblocks, и в некоторых случаях может приводить к невыполнению цикла for.
      На заметку: В условии for почему-то нет модулей.

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #include <stdio.h>
    #include <conio.h>
    #include <math.h>
    int main ()
    {
      int x;
        int p;
      p=3.3*pow(x,2)+7.7*x-10;
      while (x<10)
      {  printf("p=%d\n");
      x ++;
      }

      getchar();
    }


      • 1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        #include <stdio.h>
        #include <conio.h>
        #include <math.h>
        int main ()
        {
          int x;
          int p;
          
          while (x<10){
          p = 3.3*pow(x, 2)+7.7*x-10;
            printf("p=%d\n", p);
          x ++;
          }

          getchar();
        }
        видимо имелось в виду как то так, иначе программа вообще не имеет смысла

        • Елена Вставская
          Только задать начальное значение x и не забыть, что p - не целое число!

  • Добрый день, Елена. Хоббийно пописываю на асме, с программированием никак не связан. И периодически натыкаюсь на примеры кода написанные на Си. Десятки раз пытался с этим Си разобраться, но как то всё "не заходило". А тут в очередной раз понадобилось переложить Си на Ассемблер, в частности цикл при инициализации микросхемы и пока ждал помощи на сайте от Сишников, по поиску "Си команда for" набрел на ваш сайт. И мало того что с помощью этой странички самостоятельно разобрался с вопросом. На форуме, кстати, так толком мне и не помогли. Но ещё с удивлением для себя обнаружил, что Ваше объяснение языка мне понятно в принципе. Очень удобоваримо, по полочкам и без многословных отступлений в ширь и в глубь, рвущих мозг новичкам. Большое спасибо за Ваш сайт!

  • Почему написано "Оператор break позволяет выйти из цикла, не завершая его"? В любом другом источнике написано оператор break выводит из цикла

  • Владимир
    Елена, изучая пример работы с COM-портом в Qt Creator, встретил непонятный синтаксис оператора for

    const auto infos = QSerialPortInfo::availablePorts(); for (const QSerialPortInfo & info : infos) { //считывание данных каждого подключенного порта }

    проект собирается, компилируется, работает. Но как понять такой синтаксис?

    • Елена Вставская
      Да, есть такой синтаксис. Он перебирает поочередно все элементы внутри коллекции, которой в данном случае является infos

      • Владимир
        Спасибо, Елена! C Вашей помощью нашел такое описание https://docs.microsoft.com/ru-ru/cpp/cpp/range-based-for-statement-cpp?view=vs-2017 разобрался.

  • наверное это сила привычки, но почему вы пишите, например sum = sum +i вместо sum += i? А вообще очень хороший сайт, всё понятно и по полочкам


  • Евгений
    Доброго времени суток, уважаемая Елена! Прежде всего хочу Вас поблагодарить за отличный материал! Может быть я ошибаюсь, в предоставленном коде в разделе "Пример на Си: Посчитать сумму чисел от 1 до введенного k" должно быть не "sum = sum + i", а "sum = sum + k"? Так как i в данном случае счётчик :)

    • Елена Вставская
      Нет, если считать sum=sum+k, то мы число k сложим k ра, то есть посчитаем k*k

  • В каких случаях используется именно "%2d" вместо привычного "%d" и на сколько это необходимо?

    • Елена Вставская
      Цифры в формате вывода обозначают количество знакомест, отводимых для вывода числа. %2d отводит для вывода числа 2 знакоместа. В результате числа 1 и 10 при выводе друг под другом будут выравниваться по правому краю.

    • %2d это обычный спецификатор целого числа, а двойка означает вывод целого числа после двух пропущенных клеток (тип два пробела)

      • Елена Вставская
        Двойка означает, что для вывода числа отводится два знакоместа. Числа из одного и двух знаков в этом случае будут выравниваться по разряду единиц. Если число трёхзначное, то двойка в формате игнорируется.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *