Имеется еще несколько вариаций оператора for, увеличивающие его мощь и гибкость в некоторых ситуациях.
Одна из наиболее типичных вариаций достигается с использованием оператора «запятая», тем самым позволяя две или более переменных цикла. Оператор «запятая» используется для объединения нескольких выражений. Например, данный цикл использует переменные х и у для управления циклом и обе эти переменные инициализируются в операторе for:
for (x = 0, y = 0; x +y < 10; ++x) {
scanf(“%d”, y);
. . .
}
Здесь оператор «запятая» разделяет два инициализационных оператора. При каждом увеличении х цикл повторяется и значение у вводится с клавиатуры. Как х, так и у должны иметь корректное значение для окончания цикла. Необходимо инициализировать переменную у нулем, поэтому ее значение определяется перед первым вычислением выражения условия. Если бы уне была определена, то имелся бы шанс, что в результате предыдущей работы программы она содержала 10, делая тем самым условие проверки ложным и запрещая выполнение тела цикла.
Другой пример использования нескольких переменных цикла можно найти в показанной ниже функции reverse(). Она предназначена для копирования значения первого строкового аргумента в второй строковый аргумент в обратном порядке. Например, если функция вызывается с параметром “hello” для s, то после окончания работы функции rполучит “olleh”:
/* Копирование s в r в обратном порядке */
reverse(char *s, char *r)
{
int i, j;
for (i = strlen(s) – 1, j = 0; i >= 0; j++, i--) r[i] = s[j];
Не обязательно в качестве условия использовать простое сравнение переменной цикла с некоторым целевым значением. Фактически условием может выступать оператор отношения или логический оператор. Например, данная функция может быть использована для регистрации пользователя на удаленной системе. Пользователю предоставляется три шанса ввести пароль. Цикл оканчивается в случае использования всех трех возможностей или введения правильного пароля:
sign_on()
{
char str[20];
int x;
for (x = 0; x <3 && strcmp(str, “password”); ++x) {
printf(“Введите пароль: “);
gets(str);
}
if (x= =3) hang_up();
}
Надо помнить, что strcmp() – это стандартная библиотечная функция, выполняющая сравнение двух строк и возвращающая 0 в случае совпадения.
Другая интересная вариация цикла for основана на том, что любая из трех частей цикла может содержать любое корректное выражение. Эти выражения могут и не выполнять действий, характерных для данной части. Рассмотрим следующий пример:
#include <stdio.h>
int readnum(), prompt();
int sqrnum(int num);
main()
{
int t;
for (prompt(); t = readnum(); prompt()) sqrnum(t);
}
int prompt()
{
printf(“: “);
}
int readnum()
{
int t;
scanf(“%d”, &t)
return t;
}
int sqrnum(int num)
{
printf(“%d\n”, num*num);
}
Если внимательно посмотреть на цикл for в main(), то можно увидеть, что каждая часть цикла содержит вызовы функций, которые осуществляют подсказку и чтение вводимого с клавиатуры числа. Если введенное число равно нулю, цикл оканчивается, поскольку условие ложно, иначе число возводится в квадрат. Следовательно, в данном цикле части инициализации и увеличения используются не традиционно, но абсолютно корректно.
Еще один интересный момент цикла for – это необязательность наличия какой-либо части. Практически можно опустить любую часть. Например, следующий цикл работает до тех пор, пока не будет введено число 123:
for (x = 0; x != 123; ) scanf(“%d”, &x);
Обратим внимание, что часть увеличения отсутствует. Это означает, что на каждой итерации цикла х проверяется на совпадение с числом 123, но больше ничего не выполняется. Если ввести с клавиатуры число 123, условие станет ложным и цикл прекратится.
Часто можно видеть часть инициализации вне оператора for. Это встречается, когда начальное состояние переменной цикла вычисляется неким сложным образом. Например:
gets(s); /* чтение строки в s */
if (*s) x = strlen(s); /* вычисление длины строки */
for ( ; x < 10; ) {
printf(“%d”, x);
++x;
}
Здесь инициализация пуста и хинициализируется до входа в цикл.