Опубликован: 05.07.2006 | Уровень: для всех | Доступ: платный
Лекция 4:

Управление потоком

< Лекция 3 || Лекция 4: 12345 || Лекция 5 >

3.6. Цикл DO - WHILE

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

do 
      оператор while (выражение)

Сначала выполняется оператор, затем вычисляется выражение. Если оно истинно, то оператор выполняется снова и т.д. Если выражение становится ложным, цикл заканчивается.

Как и можно было ожидать, цикл do-while используется значительно реже, чем while и for, составляя примерно пять процентов от всех циклов. Тем не менее, иногда он оказывается полезным, как, например, в следующей функции itoa, которая преобразует число в символьную строку (обратная функции atoi ). Эта задача оказывается несколько более сложной, чем может показаться сначала. Дело в том, что простые методы выделения цифр генерируют их в неправильном порядке. Мы предпочли получить строку в обратном порядке, а затем обратить ее.

itoa(n,s)   /*convert n to characters in s */
char s[];
int n;
{
int i, sign;

if ((sign = n) < 0)   /* record sign */
   n = -n;     /* make n positive */
i = 0;
do {    /* generate digits in reverse order */
   s[i++] = n % 10 + '0';/* get next digit */
}   while ((n /=10) > 0); /* delete it */
if (sign < 0)
   s[i++] = '-'
s[i] = '\0';
reverse(s);
}

Цикл do-while здесь необходим, или по крайней мере удобен, поскольку, каково бы ни было значение n, массив s должен содержать хотя бы один символ. Мы заключили в фигурные скобки один оператор, составляющий тело do-while, хотя это и не обязательно, для того, чтобы торопливый читатель не принял часть while за начало оператора цикла while.

Упражнение 3-3

При представлении чисел в двоичном дополнительном коде наш вариант itoa не справляется с наибольшим отрицательным числом, т.е. со значением n равным -2 в степени м-1, где м размер слова. объясните почему. Измените программу так, чтобы она правильно печатала это значение на любой машине.

Упражнение 3-4

Напишите аналогичную функцию itob(n,s), которая преобразует целое без знака n в его двоичное символьное представление в s. Запрограммируйте функцию itoh, которая преобразует целое в шестнадцатеричное представление.

Упражнение 3-5

Напишите вариант itoa, который имеет три, а не два аргумента. Третий аргумент - минимальная ширина поля; преобразованное число должно, если это необходимо, дополняться слева пробелами, так чтобы оно имело достаточную ширину.

3.7. Оператор BREAK

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

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

#define maxline 1000
main()    /* remove trailing blanks and tabs */
{
int n;
char line[maxline];

while ((n = getline(line,maxline)) > 0) {
 while (--n >= 0)
       if (line[n] != ' ' && line[n] != '\t'
       && line[n] != '\n')
             break;
 line[n+1] = '\0';
 printf("%s\n",line);
}
}

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

В качестве альтернативы к break можно ввести проверку в сам цикл:

while ((n = getline(line,maxline)) > 0) {
 while (--n >= 0
     && (line[n] == ' ' || line[n] == '\t'
     || line[n] == '\n'))
           ;
   ...
}

Это уступает предыдущему варианту, так как проверка становится труднее для понимания. Проверок, которые требуют переплетения &&, ||, ! и круглых скобок, по возможности следует избегать.

< Лекция 3 || Лекция 4: 12345 || Лекция 5 >
Ярослав Воробей
Ярослав Воробей
Россия
Дмитрий Левин
Дмитрий Левин
Россия