C1
- egorcobra
- 16 дек. 2015 г.
- 7 мин. чтения
Тема: Исправление ошибок в простой программе с условными операторами.
Что нужно знать:
правила построения программы на Паскале1, Бэйсике или Си
правила работы с переменными (объявление, ввод, вывод, оператор присваивания)
ветвление – это выбор одного из двух возможных вариантов действий в зависимости от того, выполняется ли некоторое условие;
на блок-схеме алгоритма ветвление изображается в виде блока-ромба с одним входом и двумя выходами:

если условие, записанное внутри ромба, истинно (ответ «да» на вопрос «a=b?»), выполняются все команды, входящие в блок-1 (ветка «да»), иначе (если условие ложно) выполняются все команды в блоке-2 (ветка «нет»)
в неполной форме условного оператора блок-2 пустой (отсутствует); теоретически можно сделать наоборот – так, чтобы блок-1 оказался пустой, но это очень неграмотное решение, поскольку оно осложняет понимание алгоритма, запутывает его
одна команда ветвления может находиться внутри другой, например, так:

на этой схеме блок-10 выполняется, когда a=b; блок-11 – когда a=b=c, блок-12 – когда a=b, но a<>c и, наконец, блок-2 – когда a<>b
на этой схеме (Рисунок 3) одна команда ветвления (с условием «a=c») вложена в другую (с условием «a=b»), каждая из них – это ветвление в полной форме; если блок-12 будет пустой (отсутствует), внутреннее ветвление имеет неполную форму; аналогично, если блок-2 пустой, то внешнее ветвление имеет неполную форму
условный оператор if–else служит для организации ветвления в программе на языке Паскаль
условный оператор может иметь полную или неполную форму; вот фрагменты программы, реализующие ветвления, показанные на рисунках 1 и 2:

здесь вместо комментариев в фигурных скобках (они выделены синим цветом) могут стоять любые операторы языка программирования (в том числе операторы присваивания, другие условные операторы, циклы, вызовы процедур и т.п.)
обычно при записи программы операторы, находящиеся внутри обоих блоков, сдвигают вправо на 2-3 символа (запись «лесенкой»), это позволяет сразу видеть начало и конец блока (конечно, если «лесенка» сделана правильно)
после else не надо (нельзя!) ставить какое-то условие, эта часть выполняется тогда, когда условие после if неверно (частая ошибка – после else пытаются написать условие, обратное тому, которое стоит после соответствующего ему if)
в Паскале перед else не ставится точка с запятой, поскольку это ключевое слово обозначает не начало нового оператора, а вторую часть условного оператора if–else
слова begin и end (их называют также «операторные скобки») ограничивают блок-1 и блок-2; если внутри блока всего один оператор, эти «скобки» можно не писать, например, допустимы такие операторы

а вот такие операторы недопустимы

в первом случае есть begin, но забыли про соответствующий ему end;
во втором фрагменте наоборот, есть end, а begin отсутствует;
третий случай более сложный: судя по записи «лесенкой», здесь внутри блока-1 находятся 2 оператора, а операторных скобок begin-end нет; в результате получилось, что оператор c:=1 находится внутри блока-1, он выполняется только при условии a=b; оператор d:=1 выполняется всегда, после того, как условный оператор закончил работу; а else вообще «висит» непонятно как, тут транслятор выдаст ошибку; исправить эту программу можно так, как показано справа (добавив пару begin-end):

условный оператор может находиться внутри другого условного оператора, как в блоке-1, так и в блоке-2; например, схема на Рисунке 3 может быть записана на Паскале так:

ключевая тема этого задания ЕГЭ – использование вложенных условных операторов, причем в тексте задания фрагмент программы обычно записан без отступов «лесенкой» или с неправильными отступами, например, так:

Чтобы разобраться с работой этих программ, нужно определить, к какому из условных операторов if относится часть else; для этого используют такое правило: «любой else относится к ближайшему if».
Рассмотрим фрагмент слева, в нем перед else стоит end, поэтому для него нужно найти соответствующий ему begin; таким образом определяем, что else относится к первому (внешнему) условному оператору.
В правом фрагменте перед else нет end, поэтому он относится к ближайшему по тексту внутреннему условному оператору.
Блок-схемы для двух фрагментов показаны ниже, желтым цветом выделен «переехавший» блок:

в условных операторах можно использовать сложные условия, которые строятся из простых отношений (<, <=, >, >=, =, <>) с помощью логических операций not («НЕ», отрицание), and («И», одновременное выполнение двух условий) и or («ИЛИ», выполнение хотя бы одного из двух условий)
в сложном условии сначала выполняются действия в скобках, потом – not, затем – and, затем – or и, наконец, отношения; операции равного уровня (приоритета) выполняются последовательно слева направо
поскольку отношения в Паскале имеют низший приоритет, в сложном условии их приходится брать в скобки:
if (a = b) or (b < c) and (c <> d) then begin
...
end;
в приведенном выше примере сначала определяются результаты сравнения (выражения в скобках), затем выполняется операция and («И»), а затем – or («ИЛИ»)
Пример задания:
На обработку поступает последовательность из четырёх неотрицательных целых чисел (некоторые числа могут быть одинаковыми). Нужно написать программу, которая выводит на экран количество нечётных чисел в исходной последовательности и максимальное нечётное число. Если нечётных чисел нет, требуется на экран вывести «NO». Известно, что вводимые числа не превышают 1000. Программист написал программу неправильно. Вот она:

Последовательно выполните следующее.
1. Напишите, что выведет эта программа при вводе последовательности: 2 9 4 3
2. Приведите пример такой последовательности, содержащей хотя бы одно нечётное число, что, несмотря на ошибки, программа печатает правильный ответ.
3. Найдите все ошибки в этой программе (их может быть одна или несколько). Известно, что каждая ошибка затрагивает только одну строку и может быть исправлена без изменения других строк. Для каждой ошибки:
1) выпишите строку, в которой сделана ошибка;
2) укажите, как исправить ошибку, т.е приведите правильный вариант строки. Обратите внимание, что требуется найти ошибки в имеющейся программе, а не написать свою, возможно, использующую другой алгоритм решения. Исправление ошибки должно затрагивать только строку, в которой находится ошибка.
Решение:
Последовательно выполните следующее:
1. Перерисуйте и заполните таблицу, которая показывает, как работает программа при аргументах, принадлежащих различным областям (A, B, C, D, E, F и G). Точки, лежащие на границах областей, отдельно не рассматривать.
В столбцах условий укажите "да", если условие выполнится, "нет" если условие не выполнится, "—" (прочерк), если условие не будет проверяться, «не изв.», если программа ведет себя по-разному для разных значений, принадлежащих данной области. В столбце "Программа выведет" укажите, что программа выведет на экран. Если программа ничего не выводит, напишите "—" (прочерк). Если для разных значений, принадлежащих области, будут выведены разные тексты, напишите «не изв». В последнем столбце укажите "да" или "нет".
2. Укажите, как нужно доработать программу, чтобы не было случаев ее неправильной работы. (Это можно сделать несколькими способами, поэтому можно указать любой способ доработки исходной программы) .
Решение:
обратим внимание на две строки в начале программы, которые начинаются с ключевого слова var: это не ошибка, такое повторение, действительно, допустимо в языке Паскаль; возможно, это была одна из ловушек разработчиков КИМ, которую они применили на реальном ЕГЭ-2014
теперь выполним программу для заданной последовательности 2 9 4 3, записывая все изменения переменных в таблицу:

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

поскольку все числа по условию неотрицательны и не превышают 1000, программа всегда будет выдавать 999 вместо максимального нечётного числа; в то же время мы выяснили, что количество нечётных чисел в последовательности считается правильно; поэтому любая последовательность, содержащая 999, будет обрабатываться правильно
таким образом, правильный ответ на п. 2 должен быть таким:

теперь будем искать ошибки; как уже отмечалось, повторное использование ключевого слова var допустимо и указывать это в качестве ошибки нельзя!
как следует из результатов ручной прокрутки программы, во многих случаях она выдаёт неверный результат из-за того, что неверно задано начальное значение переменной maximum: оно должно быть меньше, чем любой возможный результат;
наименьшее нечётное неотрицательное число – это 1, поэтому можно принять в качестве начального значения maximum любое число, меньшее единицы (на самом деле, программа будет правильно работать и для 1), например:

если теперь (с исправленной первой ошибкой) сделать ручную прокрутку программы, то мы увидим, что на последовательности 2 9 4 3 она выдает сначала 2, а потом – 4, то есть, значение максимума вычисляется опять неверно;
откуда появится число 4 в переменной maximum? оно будет записана в результате выполнения оператора if x > maximum then maximum:=i, который записывает в переменную maximum не значение полученного числа (x), а его номер (i); таким образом, мы нашли вторую ошибку:

Ещё пример задания:
Требовалось написать программу, которая вводит с клавиатуры координаты точки на

плоскости (x, y – действительные числа) и определяет принадлежность точки заштрихованной области, включая ее границы. Программист торопился и написал программу неправильно. Вот она:

Последовательно выполните следующее:
1. Перерисуйте и заполните таблицу, которая показывает, как работает программа при аргументах, принадлежащих различным областям (A, B, C, D, E, F и G). Точки, лежащие на границах областей, отдельно не рассматривать. В столбцах условий укажите "да", если условие выполнится, "нет" если условие не выполнится, "—" (прочерк), если условие не будет проверяться, «не изв.», если программа ведет себя по-разному для разных значений, принадлежащих данной области. В столбце "Программа выведет" укажите, что программа выведет на экран. Если программа ничего не выводит, напишите "—" (прочерк). Если для разных значений, принадлежащих области, будут выведены разные тексты, напишите «не изв». В последнем столбце укажите "да" или "нет".
2. Укажите, как нужно доработать программу, чтобы не было случаев ее неправильной работы. (Это можно сделать несколькими способами, поэтому можно указать любой способ доработки исходной программы) .
Решение:
начнем заполнять таблицу, выписывая истинность каждого из трёх условий
условие y>=x истинно выше прямой y=x, то есть в областях A, B, E, F

условие y>=0 истинно выше прямой y=0, то есть в областях A, E, G, однако это условие проверяется только тогда, когда первое условие, y>=x, истинно; поэтому для всех областей, где первое условие неверно (это области C, D, G), сразу в столбце второго условия ставим прочерк (условие не будет проверяться)

третье условие выполняется для областей «внутри» параболы, то есть для E, F, G, D; однако оно проверяется только тогда, когда первые два истинны (для А и Е), в остальных строках ставим прочерк:

как следует из текста программы, она выведет что-то на экран только в том случае, когда выполняются первые два условия и программа выходит на третье: для области А будет выведено «не принадлежит», для области Е – «принадлежит», именно в этих двух случаях программа работает правильно, в остальных – нет:

для того, чтобы доработать программу, проще всего составить одно сложное условие, описывающее всю заштрихованную область
в данном случае удобно представить данную область в виде объединения областей, первая из которых включает области E+G, а вторая – области E+F
область E+G соответствует условию (y>=0) and (y <=2-x*x)
область E+F соответствует условию (y>=x) and (y <=2-x*x)
объединение областей выполняется с помощью операции ИЛИ (or), так что полное условие принимает вид (y>=0) and (y <=2-x*x) or (y>=x) and (y <=2-x*x); поскольку операция И (and) имеет более высокий приоритет, чем ИЛИ (or), порядок выполнения операций тут правильный; в случае сомнений можно поставить дополнительные скобки:
((y>=0) and (y <=2-x*x)) or ((y>=x) and (y <=2-x*x))
поскольку в обоих условиях есть условие y <=2-x*x, запись можно немного сократить:
доработанная программа выглядит так:

Kommentare