Язык программирования Си. Издание 3-е, исправленное
Шрифт:
Мораль такова: писать программы, зависящие от очередности вычислений, - плохая практика, какой бы язык вы ни использовали. Естественно, надо знать, чего следует избегать, но если вы не знаете, как образуются побочные эффекты на разных машинах, то лучше и не рассчитывать выиграть на особенностях частной реализации.
Глава 3. Управление
Порядок, в котором выполняются вычисления, определяется инструкциями управления. Мы уже встречались с наиболее распространенными управляющими конструкциями такого рода в предыдущих примерах; здесь мы завершим их список и более точно определим рассмотренные ранее.
3.1 Инструкции и блоки
Выражение, скажем x = 0,
В Си точка с запятой является заключающим символом инструкции, а не разделителем, как в языке Паскаль.
Фигурные скобки { и } используются для объединения объявлений и инструкций в составную инструкцию, или блок, чтобы с точки зрения синтаксиса эта новая конструкция воспринималась как одна инструкция. Фигурные скобки, обрамляющие группу инструкций, образующих тело функции, - это один пример; второй пример - это скобки, объединяющие инструкции, помещенные после if, else, while или for. (Переменные могут быть объявлены внутри любого блока, об этом разговор пойдет в главе 4.) После правой закрывающей фигурной скобки в конце блока точка с запятой не ставится.
3.2 Конструкция if-else
Инструкция if-else используется для принятия решения. Формально ее синтаксисом является:
причем else– часть может и отсутствовать. Сначала вычисляется выражение, и, если оно истинно (т. е. отлично от нуля), выполняется инструкция1. Если выражение ложно (т. е. его значение равно нулю) и существует else– часть, то выполняется инструкция2.
Так как if просто проверяет числовое значение выражения, условие иногда можно записывать в сокращенном виде. Так, запись
короче, чем
Иногда такие сокращения естественны и ясны, в других случаях, наоборот, затрудняют понимание программы.
Отсутствие else– части в одной из вложенных друг в друга if– конструкций может привести к неоднозначному толкованию записи. Эту неоднозначность разрешают тем, что else связывают с ближайшим if, у которого нет своего else. Например, в
else относится к внутреннему if, что мы и показали с помощью отступов. Если нам требуется иная интерпретация, необходимо должным образом расставить фигурные скобки:
Ниже
С помощью отступов мы недвусмысленно показали, что нам нужно, однако компилятор не воспримет эту информацию и отнесет else к внутреннему if. Искать такого рода ошибки особенно тяжело. Здесь уместен следующий совет: вложенные if обрамляйте фигурными скобками. Кстати, обратите внимание на точку с запятой после z = a в
Здесь она обязательна, поскольку по правилам грамматики за if должна следовать инструкция, а выражение-инструкция вроде z = a; всегда заканчивается точкой с запятой.
3.3 Конструкция else-if
Конструкция
встречается так часто, что о ней стоит поговорить особо. Приведенная последовательность инструкций if– самый общий способ описания многоступенчатого принятия решения. Выражения вычисляются по порядку; как только встречается выражение со значением "истина", выполняется соответствующая ему инструкция, на этом последовательность проверок завершается. Здесь под словом инструкция имеется в виду либо одна инструкция, либо группа инструкций в фигурных скобках.
Последняя else– часть срабатывает, если не выполняются все предыдущие условия. Иногда в последней части не требуется производить никаких действий, в этом случае фрагмент
можно опустить или использовать для фиксации ошибочной ("невозможной") ситуации.
В качестве иллюстрации трехпутевого ветвления рассмотрим функцию бинарного поиска значения x в массиве v. Предполагается, что элементы v упорядочены по возрастанию. Функция выдает положение x в v (число в пределах от 0 до n-1), если x там встречается, и -1, если его нет.
При бинарном поиске значение x сначала сравнивается с элементом, занимающим серединное положение в массиве v. Если x меньше, чем это значение, то областью поиска становится "верхняя" половина массива v, в противном случае - "нижняя". В любом случае следующий шаг - это сравнение с серединным элементом отобранной половины. Процесс "уполовинивания" диапазона продолжается до тех пор, пока либо не будет найдено значение, либо не станет пустым диапазон поиска. Запишем функцию бинарного поиска: