Остерегайтесь логических ошибок

Ранее в этой работе мы приводили пример программы для расчета недельного заработка (см. Листинг 4). Компиляция этой программы пройдет без ошибок, и вы можете пользоваться ею некоторое время, прежде чем обнаружится главный изъян, а именно, в программе подразумевается, что служащий работает, по меньшей мере, 40 часов в неделю, или, что то же самое, минимальной возможной оплатой является оплата сорокачасовой рабочей недели. Если это действительно так, то никаких проблем не возникнет. Но что, если работник работает меньше сорока часов в неделю и должен получать зарплату в соответствии с реально отработанным временем? Если в эту программу ввести значение отработанных часов меньшее, чем 40, все расчеты окажутся неверными. Проблема содержится в инструкции

total = (40 * rate) +((hours - 40) * (rate * 2));

Во-первых, даже если кто-то работал меньше 40 часов, все равно значение оплаты одного часа будет умножено на 40, как указано в действии 40 * rate. Во-вторых, результат операции hours - 40 окажется отрицательной величиной. Это отрицательное значение будет умножено на оплату часа работы, увеличенную вдвое, и полученный результат прибавлен к основной зарплате. Добавление отрицательной величины приведет к уменьшению исходного значения, и в результате работник потеряет из заработка оплату в двойном размере за каждый час, недостающий до40.

Решение этой проблемы приводится в следующих лабораторных работах. Пока же поиск решения представляется менее важной задачей, чем ясное понимание сущности проблемы.

Ищите образцы

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

В качестве примера возьмем знакомую программу, в которой мы использовали деление нацело, чтобы набрать определенную сумму денег (см. Листинг 2). Следующую последовательность инструкций можете рассматривать как образец:

twenties = amount / 20;r20 = amount % 20;tens = r20 / 10;r10 = r20 % 10;fives = r10 / 5;ones = r10 % 5;

Обратите внимание на то, что переменные справа от знака равенства используются дважды: один раз с оператором деления (/), второй раз с

Остерегайтесь логических ошибок - student2.ru
Рис.12. Образец в программе из Листинга 2

оператором получения остатка от деления нацело (%). Заметьте также, что результат вычисления остатка от деления нацело используется в следующей за ним строке. На рис.12 проиллюстрирован приведенный образец.

Эту программу можно легко расширить распространением приведенного образца на другие уровни. Например, если вы хотите использовать банкноты достоинством 50 долларов, то можете модифицировать программу, добавив следующие строки:

fifties = amount / 50;r50 = amount % 50;twinties = r50 / 20;r20 = r50 % 20;

В тот же образец мы добавили две новые инструкции и слегка видоизменили строку, в которой рассчитывается количество двадцатидолларовых банкнот.

Диагностические проблемы

Если вы не до конца уверены, что с результатами работы программы все обстоит благополучно, попробуйте ввести дополнительные функции printf(). Разделите весь процесс на такое количество дискретных операций, какое только возможно. После каждой операции, изменяющей значение переменной, помещайте функцию printf(), отображающую текущее значение переменной, даже если оно не интересует вас в качестве конечного результата.

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

значение regular равно 400значение extra равно -2значение d_time равно 40

отрицательное значение переменной extra, содержащей значение оплаты сверхурочных, должно немедленно насторожить вас. Можно предположить, что проблема кроется в неправильных инструкциях где-то перед функцией printf(), отображающей значение этой переменной. После исправления ошибки дополнительные инструкции вывода можно убрать из текста программы.

  Вопросы
  1. В чем заключается различие между операторами / и %?
  2. Можно ли использовать разные типы данных в одной операции? Если да, то как это отразится на результатах операции?
  3. Что такое выражение?
  4. Где можно использовать выражение?
  5. Опишите порядок приоритета арифметических операторов.
  6. Зачем при записи операций используют круглые скобки?
  7. Объясните разницу между инструкциями count=count+1 и count++.
  8. Что такое аккумулятор?
  9. Дайте описание оператора присваивания.
  10. В чем разница между --count и count--?
 
  Упражнения
  1. Напишите программу, которая сообщает пользователю, сколько лет ему будет в 2000 году.
  2. Напишите программу расчета квадрата и куба числа, введенного с клавиатуры.
  3. Напишите программу перевода температуры из шкалы Фаренгейта (F) в шкалу Цельсия (C). Формула пересчета C=(5.0/9.0)Ф(F–32).
  4. Модифицируйте программу из упражнения 3 так, чтобы она сообщала, на сколько градусов отстоит введенное значение температуры от точки замерзания по шкале Фаренгейта и по шкале Цельсия.
5. Объясните, почему следующая программа написана неверно: #define TAX_RATE 0.06main(){floatcost, total;printf("Введите стоимость единицы товара: ");scanf("%f", &cost);printf("Введите величину транспортных расходов: ");scanf("%f", &shipping);total = cost + cost * tax_rate + shipping;printf("Общая стоимость составляет %f", total);}

Наши рекомендации