Сокращенный оператор присваивания




Операторы присваивания иногда выполняют больше работы, чем нужно. В операторе

А = А + 45;

компилятор генерирует код для вычисления выражения А + 45, результат которого затем присваивается, опять переменной А. Две ссылки на переменную А требуют двукратного вычисления адреса переменной А в памяти - один раз для нахождения исходного значения А, а затем для определения адреса, по которому нужно записать результат. То же самое выражение можно записать проще, а именно:

А += 45.

Эта запись поможет компилятору сгенерировать программный код более рационально. Двойной символ += на­зывается оператором присваивания. Эта сокращенная запись дает указание компилятору прибавить число 45 к значению А и запомнить результат опять-таки в переменной А. Вот полный набор операторов присваивания:

*=, /=, +=, -=, %=, «=, »=, &=, "= и |=.

Каждый из них (ор) позволяет свести символическую запись выражения (псевдокод)

i = i op j;

к более короткой записи

i ор= j;

Замечание

Псевдокод - это неформальный способ описания операторов без использования фактических элементов языка С (или другого языка). Обозначение о p, использованное в приведенных выше псевдооператорах, -это просто концептуальное обозначение, а не фактический оператор.

Следующие несколько примеров операторов присваивания для переменной count типа int демонстрируют, как работает сокращенная запись операторов (в комментариях даны эквивалентные полные формы):

count += 10; /* count = count + 10 */

count *= 2; /* count = count * 2 */

count /= 3; /* count = count / 3 */

count %= 16; /* count = count % 16 */

Такие оптимизирующие компиляторы, как Borland C++, способны генерировать эффективный програм­мный код и для эквивалентных полных выражений, но в сложных выражениях, где участвуют не такие про­стые переменные, как count, множественные ссылки на переменные могут снизить быстродействие программы. Используйте операторы присваивания, где только это возможно. Они ускорят выполнение программы.

 

Приоритеты операторов

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

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

у = ((а * х) + b) / (х + с).

Несмотря на то что назначение этой формулы не очевидно (она описывает гиперболическую кривую), круглые скобки не оставляют сомнений относительно последовательности вычисления подвыражений.

Но, учитывая установленный приоритет операций, представленное выше выражение можно записать не­сколько иначе и получить при этом правильный результат, а именно:

у = (а * х + b) / (х + с).

Поскольку умножение и деление выполняются слева направо, то можно убрать одну пару круглых скобок в первом выражении. При этом правильность сохраняется, но ясность понимания слегка уменьшается.

Обязательно изучите приоритеты операторов и правила ассоциативности, приведенные в табл. 2.7. Но чем полагаться исключительно на приоритет операторов, добавьте лучше лишнюю пару круглых скобок - они не повлияют на быстродействие, а программа станет более понятной.

Таблица 2.7. Приоритет операторов и порядок вычисления (ассоциативность)

Уровень приоритета   Операторы   Порядок вычислений      
  ()..[ ] ->   Слева направо      
  * &! ~++-+- (тип) sizeof   Справа налево      
  * / %   Слева направо      
  + -   Слева направо      
  << >>   Слева направо      
  <<= >>=   Слева направо      
  ==!=   Слева направо   1  
  &   Слева направо      
  ^   Слева направо      
  |   Слева направо    
  &&   Слева направо    
  ||   Слева направо    
  ?:   Справа налево    
  = *= /= += -= %= <<= >>= &= ^= |=   Справа налево    
  ‘   Слева направо    
         

 

Замечание

Унарный плюс (+) и унарный минус (-) находятся на уровне 2, и их приоритет выше, чем у арифметических плюса и минуса, находящихся на уровне 4. Символ & на уровне 2 является оператором взятия адреса, а сим­вол & на уровне 8 представляет поразрядный оператор И. Символ * на уровне 2 - это оператор разыменова­ния, а символ на уровне 3 означает оператор умножения. При отсутствии круглых скобок операторы одного уровня вычисляются в соответствии сих порядком вычислений.

Оператор if

Оператор if (Если) действует точно так, как ожидается. Если выражение истинно, оператор выполнит дей­ствие; в противном случае программа продолжит свою работу со следующего оператора.

В этом и следующих разделах использование псевдокода помогает объяснить различные формы операто­ров. Псевдокод оператора if имеет следующий вид:

if (.выражение)

оператор;

Выражением может служить любое выражение, которое в результате дает значение "истина" или "ложь". Если выражение истинно (ненулевое), то оператор выполняется. Если выражение ложно (нуль), то опера­тор пропускается. Можно записывать операторы if в одной строке:

if (выражение) оператор;

Но обычно оператор if пишется на отдельных строчках, что позволяет выделить его компоненты. Оператор может быть составным:

if (.выражение) {

оператор 1;

оператор 2;

}

Расположение фигурных скобок в составном операторе if строго не регламентируется. Некоторые програм­мисты предпочитают их выравнивать следующим образом:

if (выражение)

{

оператор 1,

оператор 2;

}

Кроме того, для записи сравниваемых выражений можно использовать оператор отношения:

if (выражение == значение)

оператор;

Оператор будет выполнен только в том случае, если выражение равно значению. Не следует записывать операторы if в таком виде:

if (выражение = значение) /*??? */

опера тор;

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

Опытные программисты (которые, возможно, не такие большие специалисты по вводу программ) часто со­кращают выражения оператора if до минимума. "Ободранный как липка" оператор

if (выражение!= 0)

оператор;

функционально идентичен следующему:

if (выражение)

оператор;

А ларчик просто открывался... Все дело в том, что логические выражения (выражение != 0) и (выражение) эквивалентны, так как любое ненулевое значение является истинным. Замените выражение, например, лите­ральным значением 5, и вы поймете, в чем тут фокус. Очевидно, что 5 не равно 0, т.е. первое выражение ис­тинно. И второе также будет иметь значение "истина", поскольку 5 является ненулевым значением, а значит, истинным.

Такого рода сокращения часто встречаются в операторах if. Между записями if (выражение != 0 ) и if (выра­жение) нет никакой функциональной разницы. Но использование более длинной формы придаст вашей про­грамме большую наглядность без ущерба для стиля и быстродействия.

Листинг 2.10 показывает, как использовать оператор if. Скомпилируйте и запустите программу, затем вве­дите число от 0 до 10. Если вы введете число, выходящее за пределы этого диапазона, программа выдаст со­общение об ошибке.

Листинг 2.10. CHOICE.С (использование оператора if)

__________________________________________________

1: #include <stdio.h>

2:

3: rnain()

4: {

5: int number;

6: int okay;

7:

8: printf("Enter a number from 1 to 10: ");

9: scanf("%d", &number);

10: okay = (1 <= number) && (number <= 10);

11: if (!okay)

12: printf("Incorrect answer!\n");

13: return okav;

14: }

Строка 10 присваивает переменной okay типа int истинное или ложное значение результата выражения отношения

(1 <= number) && (number <= 10)

Результат выражения представляет собой целое значение - 0, если вычисление даст "ложь", или ненулевое значение в случае "истины". Это значение присваивается переменной okay, после чего строка 11 проверяет вы­ражение !okay (читается "не о'кей"). Если okay ложно (в случае ошибки), то!okay даст значение "истина", и тогда строка 12 выведет сообщение об ошибке.

Совет

Для запоминания выражений отношений в операторах if выбирайте идентификаторы, подобные okay, вместо сложных и ничего не значащих имен. Тщательно выбранные идентификаторы сослужат хорошую службу для понимания текста программы.

Строка 13 возвращает значение переменной okay ("истину" или "ложь") обратно в DOS, хотя в данном случае это просто демонстрация такой возможности. Но в более сложных программах аналогичное возвращае­мое значение может означать обнаружение серьезной ошибки.

Вы можете также записывать сложные логические выражения непосредственно в операторах if. Например, вы можете соединить строки 10-12 в один оператор:

if ((1 <= number) && (number <= 10))

printf("Incorrect answer!\n");

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

Оператор else

Оператор else (Иначе) является расширением оператора if. После любого оператора if вы можете вставить оператор else для выполнения альтернативного действия. Используйте else следующим образом:

if (выражение)

оператор 1;

else

oneparop 2;

Если выражение истинно (ненулевое), выполняется onepamop1; в противном случае — onepamop2. Опера­торы могут быть простыми или составными. Вы можете записать:

if (выражение) {

оператор 1;

оператор 2;

} else

оператор З;

Составными могут быть обе части, заключенные в фигурные скобки:

if (выражение) {

оператор 1;

оператор 2;

} else {

оператор 3;

оператор 4;

}

В этой конструкции выполнятся операторы 1 и 2, если выражение окажется истинным; в противном случае будут выполнены операторы 3 и 4.

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

Как и в простых операторах if, расположение фигурных скобок в сложных конструкциях if-else - дело вкуса программиста. Некоторые программисты предпочитают выравнивать фигурные скобки так:

if (выражение)

{

оператор 1;

оператор 2;

}

else

{

оператор З;

оператор 4;

}

Вы можете вкладывать несколько конструкций if-else друг в друга, создавая многовариантный выбор:

if (выражение 1)

оператор 1;

else if (выражение 2)

оператор 2;

else

оператор З;

Давайте разберемся, как работает такая конструкция. Если выражение 1 истинно, то выполняется onepamop 1; если истинно выражение 2, то выполняется onepamop 2. Если выражение 1 и выражение 2 имеют значение "ложь", то выполняется оператор З. Можно развить эту идею дальше:

if (выражение 1)

оператор 1;

else if (выражение 2)

оператор 2;

else if (выражение З)

оператор З;

else if (выражение N)

оператор N;

else /* необязательно */

оператор_умолчания; /* необязательно */

Вложенные операторы if-else полезны для выбора одного из нескольких возможных действий, причем гаран­тируется выполнение оператора (или операторов), связанного с первым истинным выражением. Если ни одно из выражений не имеет значения "истина", выполняется последний (необязательный) оператор _умолчания.

Листинг 2.11, являясь примером использования вложенных операторов if-else, определяет високосные го­ды. Скомпилируйте и запустите программу, затем введите год, например 2000. Год, открывающий новое столетие, является високосным, если без остатка делится на 400. (На самом деле, поскольку нет года с номером 0, первым годом XXI столетия будет 2001 -й год, но не будем придираться.) Промежуточные годы (такие как 1996) будут високосными, если без остатка делятся на 4.

 

Листинг 2.11. LEAP.С (использование конструкции if-else для определения високосного года)

_____________________________________________________________________

1: #include <stdio.h>

2:

3: main()

4: {

5: int leapYear;

6: int year;

7:

8: printf("Leap Year Calculator\n");

9: printf("Year? ");

10: scanf("%d", &year);

11: if (year > 0) {

12: if ((year % 100) == 0)

13: leapYear = ((year % 400) == 0);

14: else

15: leapYear = ((year % 4) == 0);

16: if (leapYear)

17: printf("%d is a leap year\n", year);

18: else

19: printf("%d is not a leap year\n", year);

20: }

21: return 0;

22: }

_____________________________________________________

Оператор if-else, содержащий ошибку (чаще всего, это неправильное расположение фигурных скобок или их отсутствие), может привести к неправильной работе всей программы. Листинг 2.12 демонстрирует ис­порченный вариант программы.

 

Листинг 2.12. BADIF.C (неправильный способ вложенности операторов if-else)

_______________________________________________________________________

1: #include <stdio.h>

2:

3: main()

4: {

5: int value;

6:

7: printf("Value(1...10)? ");

8: scanf("%d", &value),

9: if (value >= 1)

10: if (value > 10)

11: printf("Error: value > 10\n");

12: else

13: printf("Error: value < 1\n");

14: return 0;

15: }

Запустите BADIF и введите число от 1 до 10. Предполагалось, что числа, не входящие в этот диапазон, будут отброшены, но эта программа бракует числа именно из заданного диапазона и некоторые, лежащие за его пределами. Оператор if сравнивает введенное число с единицей, и если оно больше или равно 1, то внут­ренний оператор if сравнивает его с 10. Если ваше число больше 10, будет выдано первое сообщение об ошиб­ке. Проблема в том, что код не работает так, как ожидается.

Во всем виноват оператор else на строке 12. Несмотря на то, что он выравнивается с оператором if в строке 9, он логически связан с ближайшим оператором if, находящимся выше, - в данном случае с оператором if на строке 10. Вот в этом и заключен корень зла. Теперь ваша задача - исправить программу так, чтобы опе­ратор else работал в одной связке с нужным оператором if.

Запомните такое правило: чтобы проверить логику программы, никогда не полагайтесь на сделанные вами отступы. Они только для вас, компилятор не обращает на них никакого внимания. А вот фигурные скобки за­ставят его прислушаться к вашим пожеланиям относительно вложенных операторов if-else. Листинг 2.13 де­монстрирует исправленный вариант программы.

 

Листинг 6.13. GOODIF.C (правильная вложенность операторов if-else)

___________________________________________________________

1: #include <stdio.h>

2:

3: main()

4: {

5: int value;

6:

7: printf("Value (1... 10)? “);

8: scanf("%d", &value);

9: if (value >= 1) {

10: if (value > 10)

11: printf("Error: value> 10\n");

12: } else

13: printf("Error; value < 1\n");

14: return 0;

15: }

__________________________________________________

Сравните листинги 2.12 и 2.13. Дополнительные фигурные скобки в строках 9 и 12 заставляют оператор else работать вместе с оператором if в строке 9. А внутренний оператор if в строках 10-11 сейчас работает правильно.

Условные выражения

Сокращенный оператор if-else, называемый условным выражением, иногда очень полезен. Псевдокод ус­ловного выражения выглядит следующим образом:

Выражение 1? выражение 2: выражение З;

Программа вычисляет выражение 1. Если оно истинно, то результат всего выражения равен выражению 2. Если же выражение 1 ложно, результат равен выражению З. Условное выражение в точности эквивалентно оператору if-else:

if (выражение 1)

выражение 2;

else

выражение З;

Назначение оператора if-else по сравнению с эквивалентным условным выражением обычно более понятно. Рассмотрим этот факт в связи с выбором одной из этих двух форм.

Обычно вы присваиваете результат условного выражения какой-нибудь переменной. Предположим, вы пи­шете программу, управляемую меню. Если переменная типа int menuChoice будет равна ' Y ', вы хотите устано­вить переменную testValue, равную 100; в противном случае равную нулю. Прямое решение использует опера­тор if-else:

if (menuChoice== 'Y')

testValue =100;

else

testValue =0;

Эта конструкция достаточно ясна, но данный оператор требует двух ссылок на переменную testValue. Чтобы обратиться к t estValue только один раз и выполнить ту же самую работу, вы можете записать:

testValue = (menuChoice == 'Y')? 100: 0;

Если выражение (menuChoice == 'Y') будет истинным,то оператор присвоит переменной testValue значение 100, если ложным - значение 0.

Не следует использовать условные выражения только потому, что они занимают одну строку вместо четы­рех. В большинстве случаев компилятор генерирует аналогичный код как для оператора if-else, так и для эк­вивалентного условного выражения. С другой стороны, чтобы избежать двух ссылок на одно и то же выраже­ние (особенно, если они имеют более сложную форму, чем в данном примере с переменной testValue), пред­почтительнее использовать условное выражение.

Оператор switch

Вложенный набор операторов if-else может выглядеть как запутанный водопровод старого дома. Система-то работает, но трудно понять, какая труба куда ведет.

Рассмотрим следующую серию операторов if-else, каждый из которых сравнивает выражение с определен­ным значением:

if (выражение == значение 1)

оператор 1;

else if (выражение == значение 2)

оператор 2;

else if (выражение == значение З}

onepaтор З;

else /* необязательно */

оператор_умолчания; /* необязательно */

Этуконструкцию можно сократить с помощью более простого оператора switch:

switch .(выражение) {

case значение 1:

оператор 1; /* выполняет if (выражение == значение 1) */

break; /* выход из оператора switch */

case значение2:

оператор 2; /* выполняет if (выражение == значение 2) */

break; /* выход из оператора switch */

case значение З:

оператор З; /* выполняет if (выражение == значение З) */

break; /* выход из оператора switch */

default:

оператор_умолчания; /* выполняется, если не было ни

одного совпадения */

}

На первый взгляд эта запись может показаться длиннее, но на практике оператор switch использовать про­ще, чем эквивалентную конструкцию if-else. За ключевым словом switch следует выражение, которое будет сравниваться с множеством значений. Внутри блока switch селекторы case сравнивают выражение с заданными значениями. Строка

case значение 1:

сравнивает значение 1 с результатом вычисления выражения оператора switch. Если результат сравнения даст значение "истина", то будет выполнен оператор (или блок операторов), следующий за строкой case. Если же результатом сравнения будет "ложь", аналогичным образом будет обрабатываться следующая строка case. По­следняя строка оператора switch (default:) - необязательная строка выбора. Она задает действия, выполняе­мые в случае, если ни одно из значений строк case не совпало со значением выражения оператора switch.

Оператор break в каждом блоке выбора case немедленно осуществляет выход из оператора switch. Опера­торы switch разработаны таким образом, что если вы напишите их без оператора break

switch(выражение) {

case значение 1:

оператор 1; /*??? */

case значение 2:

оператор 2; /*???*/

case значение З:

оператор З;

}

и выражение будет равно значению 1, то после выполнения оператора 1 последует выполнение оператора 2 и оператора 3 - вряд ли именно это входило в ваши планы. В операторе switch первый же случай сравнения, давший в результате "истину", приведет к выполнению всех последующих операторов, вплоть до оператора break или до конца оператора switch.

Замечание

Смышленые (может быть; даже слишком) программисты иногда намеренно опускают операторы break из операторов switch, чтобы позволить одному блоку case выполнять действия, перечисленные и в других блоках case. Это технически разрешено, но затрудняет процесс отслеживания результатов и создает трудности при внесении изменений. Лучше всего завершать каждый блок case своим оператором break.

Листинг 2.14 демонстрирует, как писать меню выбора, используя оператор switch. Скомпилируйте и запус­тите программу, затем введите буквы A, D, S и Q, чтобы выбрать команду. (Команды не делают ничего по­лезного, вы можете развить эту программу по своему вкусу.) Введите букву, которой не было в этом малень­ком списке, и вы увидите, как оператор switch обнаружит ошибку ввода.

 

Листинг 2.14. MENU.С (оператор switch)

_______________________________________________

1: #include <stdio.h>

2: #include <ctype.h>

3:

4: main()

5: {

6: int choice;

7:

8: printf("Menu: A(dd D(elete S(ort Q(uit: ");

9: choice = toupper(getchar());

10: switch (choice) {

11: case 'A':

12: printf(“You selected Add\n");

13: break;

14: case 'D':

15: printf(“You selected Delete\n");

16: break;

17: case 'S':

18: printf(“You selected Sort\n");

19: break;

20: case 'Q':

21: printf(“You selected Quit\n");

22: break;

23: default:

24: printf("\nIllegal choice!!!\n");

25: }

26: return choice;

27: }

_________________________________________

Чтобы прочитать символ, введенный с клавиатуры, строка 9 вызывает стандартную библиотечную функ­цию getchar(). Функция toupper() переводит этот символ в верхний регистр (делает прописным), упрощая та­ким образом определение нажатой клавиши.

Оператор switch начинается па строке 10, предлагая выбранный символ в качестве анализируемого выра­жения. Последующие блоки case сравнивают переменную choice с литеральными символами, выдавая подтверждающее сообщение в случае, если сравнение было удачным. Если совпадения с заданными буквами не случилось, блок default (строки 23-24) выведет сообщение об ошибке, i

В строке 26 программа возвращает выбранный символ. Хотя в данной программе это и не важно, но аналогичный оператор может передать результат работы меню из одной функции в другую, что определит выбор соответствующей команды.

Оператор while

Оператор while - один из трех операторов цикла, выполняющих повторяющиеся действия. Программы используют его для повторного выполнения операторов в течение всего времени, пока заданное условие истин­но. Псевдокод оператора while выглядит следующим образом:

while (выражение)

оператор;

В переводе с английского этот псевдокод можно "прочитать" так: "Пока выражение истинно, выполнять оператор". Как обычно, оператор может быть простым или составным:

while (выражение) {

оператор 1,

оператор 2;

…………

}

В таких конструкциях все операторы выполняются один за другим до тех пор, пока выражение истинно. Оператор while - также называемый циклом while - обычно выполняет, по крайней мере, один опера­тор, который влияет на заданное выражение. Иначе и не может быть, ведь в противном случае мы получили бы бесконечный цикл. Листинг 2.15 использует оператор while для счета от 1 до 10.

Листинг 2.15. WCOUNT.C (счет от 1 до 10 с помощью цикла while)

______________________________________________________

1: #include <stdio.h>

2:

3: main()

4: {

5: int counter;

6:

7: printf("while count\n");

8: counter =1;

9: while (counter <= 10) {

10: printf("%d\n", counter);

11: counter++;

12: }

13: return 0;

14:

______________________________________________________

Строка 8 инициализирует целую переменную counter, называемую управляющей переменной. Оператор while в строках 9-12 использует оператор отношения <= для сравнения значения counter с числом 10. Пока counter меньше или равно 10, будут выполняться операторы на строках 10-11. Строка 11 увеличивает counter на единицу на каждой итерации цикла, гарантируя таким образом, что цикл в конце концов закончится.

Чему будет равно значение переменной counter после окончания работы оператора while? Проверьте свою догадку, вставив следующий оператор между строками 12 и 13:

printf("counter == %d\n", counter);

Имеет ли смысл конечное значение переменной counter (11)? Чему оно будет равно, если заменить выра­жение в строке 9 на (counter < 10)? Попробуйте также изменить начальное значение counter в строке 8. Что произойдет, если присвоить начальное значение, равное 11? Будет ли цикл выполняться?

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

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

______________________________________________________

Листинг 2.16. WALPHA.C (вывод алфавита с помощью цикла while)

1: #include <stdio.h>

2:

3: main()

4: {

5: int c;

6:

7: printf(“.,, while alphabet\n");

8: с = 'А';

9: while (с<= 'Z') {

10: printf("%c”,с);

11: c++;

12: }

13: return 0;

14: }

______________________________________________________

.Выражение в строке 9 (с <= 'Z') истинно, если ASCII-значение символа меньше или равно ASCII-значению буквы z.

 

Оператор do-while

Оператор do-while является в некотором роде пе­ревернутым циклом while. Выраженный в псевдокоде, do-while языка С выглядит следующим образом;

do {

оператор;

} while (выражение);

Выполняется оператор, затем проверяется выражение. И до тех пор, пока значение этого выражения бу­дет истинным, оператор будет выполняться. Сравните эту схему работы с рассмотренным выше оператором while, который вычисляет свое выражение, прежде чем выполнить какой-нибудь оператор. Однако while вооб­ще может не выполнить ни одного оператора, если анализируемое выражение с самого начала было ложным. Но do-while всегда выполняет свои операторы, по крайней мере, один раз, так как проверка выражения осу­ществляется по завершении итерации цикла. Из этого следует основное правило, необходимое при выборе ме­жду while и do-while.

• Спросите себя: "Есть ли, по крайней мере, одно условие, при котором операторы цикла не должны выпол­няться хотя бы один раз?" Если ответом будет "Да", то, скорее всего, вам следует выбрать цикл while.

• Если ответ на предыдущий вопрос будет "Нет", то вам, вероятно, подойдет цикл do-while. Используйте этот цикл, если, безотносительно к значению проверяемого выражения, операторы в цикле должны быть выполнены, по крайней мере, один раз.

Оператор do-while может быть простым или составным. Однооператорные циклы do-while можно записы­вать в одной строке:

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

Можно также записывать их на отдельных строках, делая отступы для удобства восприятия:

do

оператор;

while (выражение);

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

 

do {

оператор;

} while (.выражение);

Многооператорные циклы do-while записывайте следующим образом:

do {

оператор 1;

оператор 2;

} while (.выражение);

Листинг 2.17 аналогичен приведенной выше программе WCOUNT, но считает от 1 до 10, используя цикл do-while..

Листинг 2.17. DWCOUNT.C (счет от 1 до 10 с помощью цикла do-while)

________________________________________________________________

1:: #include <stdio.h>

2:

3: main()

4: {.

5; int counter;

6:

7: printf("do-while count\n");

8: counter = 0;

9: do {

10: counter++;

11: printf("%d\n", counter);

12: } while (counter < 10);

13: return 0;

14: }

__________________________________________________

Кроме выполнения программы DWCOUNT на компьютере, попытайтесь выполнить ее вручную, записывая значения переменной counter на бумаге. Уясните себе, почему именно выражение (counter < 10) заканчивает цикл после отображения 10 -го значения. Почему бы не работать выражению (counter <= 10), как это было в программе WCOUNT? Проверьте свои предположения, вставив операторы printf() для отображения значения переменной counter в интересующие вас места программы (это неплохое средство отладки).

Для цикла do-while вы можете использовать любое средство проверки логического выражения. Чтобы проде­монстрировать такую многогранность, листинг 2.18 использует цикл do-while для вывода на экран алфавита.

 

Листинг 2.18. DWALPHA.C (вывод алфавита с помощью цикла do-while)

______________________________________________________________________

1: #lnclude <stdio.h>

2:

3: main()

4: {

5: int с;

6:

7: printf(“do-while alphabet\n");

8: с = 'A' - 1;'

9: do {

10: c++;

11: printf("%c", с);

12: } while (с< 'Z');

13: return 0;

14: }

_____________________________________________________

Оператор for

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

for (выражение 1; выражение 2; выражение З;) {

оператор;

}

На первый взгляд, оператор for может показаться сложным, но он станет понятнее, если его представить в виде эквивалентного оператора while. Следующий псевдокод аналогичен по своему результату предыдущему оператору for:

выражение 1;

while (выражение 2;) {

оператор;

выражение З;

}

Теоретически вы можете использовать любые выражения в цикле for, но для выражения 1, выражения 2 и выражения З некоторые типы выражений оказываются предпочтительнее. Например, для того чтобы с помо­щью цикла for посчитать от 1 до 10, возьмем переменную i типа int. Тогда мы можем записать:

for (i = 1; i <= 10; i++) /* выражения 1, 2и З */

printf("i == %d\n", i); /* оператор */

Первое выражение цикла for в этом примере присваивает начальное значение переменной i, равное 1; это действие выполняется только один раз, перед самым началом цикла. Второе выражение обычно является вы­ражением отношения, в данном случае оно будет равно "истине", если значение i меньше или равно 10. Третье, и последнее, выражение увеличивает на единицу значение переменной i, приближая, таким образом, цикл к концу.

Предыдущий оператор for, возможно, легче изобразить в виде эквивалентного цикла while:

i = 1; /* выражения 1 */

while (i <= 10) { /* выражения 2 */

printf(“i == %d\n", i); /* оператор */

i++;. /* выражения 3 */

}

Сравните версии for и while и обратите внимание на расположение каждого выражения и оператора. Обе версии функционально идентичны, и, по крайней мере, в этом простом примере компилятор сгенерирует для каждого варианта идентичный код.

Листинг 2.19 использует цикл for для отображения набора видимых ASCII-символов (это символы с значениями от 32 до 127).

 

Листинг 2.19. ASCII.С (отображение АЗСП-символов с помощью цикла for)

__________________________________________________________________

1: #include <stdio.h>

2:

3: main()

4: {

5: unsigned char с;

6:

7: for (с = 32; (с < 128); c++) {

8: if ((с % 32) == 0) printf("\n");

9: printf("%c", с);

10: }

11: printf("\n");

12: return 0;

13: }

______________________________________________________

Когда вы запустите программу ASCII, она отобразит на экране следующий 96 -символьный отчет:

!"#$%&’()*+,-./0123456789:;<=>? @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ 'abcdefghijklinnopqrstuvwxyz{|}~

Программный цикл for (строки 7-10) первоначально устанавливает управляющую переменную с типа unsigned char равной ASCII-значению символа пробела (32). Управляющее выражение (с < 128) завершает цикл после отображения последнего символа, т.е. когда переменная с станет равной 128. Выражение c++ на каждом проходе цикла увеличивает управляющую переменную на единицу.

Оператор if, находящийся внутри оператора for, сравнивает выражение (с % 32), равное остатку от деле­ния с на 32, с нулем. Если результат сравнения - значение "истина", то оператор printf() начинает новую строку. Замените 32 на 16 и вы получите вывод по 16 символов в строке. Выражения оператора for можно опустить, но в этом случае мы получаем бесконечный цикл:

for (;;); /* бесконечный цикл */

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

Между прочим, пробел между закрываю



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-08-20 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: