Чтение онлайн

на главную

Жанры

Программирование. Принципы и практика использования C++ Исправленное издание
Шрифт:

} // Ой!

• Совпадает ли количество открывающих и закрывающих скобок?

if (a<=0 // Ой!

x = f(y);

Компилятор обычно сообщает об этих ошибках “поздно”; он просто не знает, что вы имели в виду, когда забыли поставить закрывающую скобку после нуля.

• Каждое ли имя объявлено?

• Включены ли все необходимые заголовочные файлы (например,

#include "std_lib_facilities.h"
)?

• Объявлено ли каждое имя до его использования?

Правильно ли набраны все имена?

int count; /* ... */ ++Count; // Ой!

char ch; /* ... */ Cin>>c; // Ой-ой!

• Поставлена ли точка с запятой после каждой инструкции?

x = sqrt(y)+2 // Ой!

z = x+3;

В упражнениях мы привели еще больше примеров таких ошибок. Кроме того, помните о классификации ошибок, указанной в разделе 5.2.

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

keep_window_open
из заголовочного файла
std_lib_facilities.h
в конце функции
main
. В таком случае программа попросит вас ввести что-нибудь перед выходом, и вы сможете просмотреть результаты ее работы до того, как окно закроется. В поисках ошибок тщательно проверьте инструкцию за инструкцией, начиная с того места, до которого, по вашему мнению, программа работала правильно. Встаньте на место компьютера, выполняющего вашу программу. Соответствует ли вывод вашим ожиданиям? Разумеется, нет, иначе вы не занимались бы отладкой.

Часто, когда программист не видит проблемы, причина заключается в том, что вы видите не действительное, а желаемое. Рассмотрим пример.

for (int i = 0; i<=max; ++j) { // Ой! (Дважды)

for (int i=0; 0<max; ++i); // Выводим элементы вектора v

cout << "v[" << i << "]==" << v[i] << '\n';

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

• Часто, когда вы не видите проблемы, причина заключается в том, что между точкой, где программа еще работала правильно, и следующей точкой, где программа выдала неверный ответ, содержится слишком много инструкций (или выводится слишком мало информации). Большинство интегрированных сред программирования допускают пошаговую отладку программ. В конце концов, вы научитесь пользоваться этими возможностями, но при отладке простых программ достаточно расставить в нескольких местах дополнительные инструкции вывода (с помощью потока cerr). Рассмотрим пример.

int my_fct(int a, double d)

{

int res = 0;

cerr << "my_fct(" << a << "," << d << ")\n";

// ...какой-то
код...

cerr << "my_fct возвращает " << res << '\n';

return res;

}

• Вставьте инструкции для проверки инвариантов (т.е. условий, которые всегда должны выполняться; см. раздел 9.4.3) в подозрительные разделы.

Рассмотрим пример.

int my_complicated_function(int a, int b, int c)

// Аргументы являются положительными и a < b < c

{

if (!(0<a && a<b && b<c)) // ! значит НЕ, а && значит И

error("Неверные аргументы функции mcf");

// ...

}

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

assert
.

Интересно, что существует несколько эффективных способов программирования. Разные люди совершенно по-разному программируют. Многие различия между методами отладки объясняются разнообразием программ, а другие проистекают из разных образов мышления. Следует знать, что наилучшего способа отладки не существует. Просто надо помнить, что запутанный код чаще содержит ошибки. Старайтесь писать программы просто и логично, форматируйте их, и вы сэкономите время за счет отладки.

5.10. Пред- и постусловия

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

int my_complicated_function(int a, int b, int c)

// Аргументы являются положительными и a < b < c

{

if (!(0<a && a<b && b<c)) // ! значит НЕ, а && значит И

error("Неверные аргументы функции mcf");

// ...

}

Во-первых, в комментарии утверждается, какие аргументы ожидает функция, а затем происходит проверка этого условия (и генерирование исключения, если это условие нарушается). Это правильная стратегия. Требования, которые функция предъявляет к своим аргументам, часто называют предусловиями (pre-condition): они должны выполняться, чтобы функция работала правильно. Вопрос заключается в том, что делать, если предусловия нарушаются. У нас есть две возможности.

Поделиться:
Популярные книги

Черный Маг Императора 13

Герда Александр
13. Черный маг императора
Фантастика:
попаданцы
аниме
сказочная фантастика
фэнтези
5.00
рейтинг книги
Черный Маг Императора 13

Последняя Арена 4

Греков Сергей
4. Последняя Арена
Фантастика:
рпг
постапокалипсис
5.00
рейтинг книги
Последняя Арена 4

Маяк надежды

Кас Маркус
5. Артефактор
Фантастика:
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Маяк надежды

Великий перелом

Ланцов Михаил Алексеевич
2. Фрунзе
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Великий перелом

Сопротивляйся мне

Вечная Ольга
3. Порочная власть
Любовные романы:
современные любовные романы
эро литература
6.00
рейтинг книги
Сопротивляйся мне

Инквизитор Тьмы 2

Шмаков Алексей Семенович
2. Инквизитор Тьмы
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Инквизитор Тьмы 2

Мастер Разума V

Кронос Александр
5. Мастер Разума
Фантастика:
городское фэнтези
попаданцы
5.00
рейтинг книги
Мастер Разума V

Бандит 2

Щепетнов Евгений Владимирович
2. Петр Синельников
Фантастика:
боевая фантастика
5.73
рейтинг книги
Бандит 2

Истребители. Трилогия

Поселягин Владимир Геннадьевич
Фантастика:
альтернативная история
7.30
рейтинг книги
Истребители. Трилогия

Гардемарин Ее Величества. Инкарнация

Уленгов Юрий
1. Гардемарин ее величества
Фантастика:
городское фэнтези
попаданцы
альтернативная история
аниме
фантастика: прочее
5.00
рейтинг книги
Гардемарин Ее Величества. Инкарнация

Падение Твердыни

Распопов Дмитрий Викторович
6. Венецианский купец
Фантастика:
попаданцы
альтернативная история
5.33
рейтинг книги
Падение Твердыни

"Дальние горизонты. Дух". Компиляция. Книги 1-25

Усманов Хайдарали
Собрание сочинений
Фантастика:
фэнтези
боевая фантастика
попаданцы
5.00
рейтинг книги
Дальние горизонты. Дух. Компиляция. Книги 1-25

Ох уж этот Мин Джин Хо 2

Кронос Александр
2. Мин Джин Хо
Фантастика:
попаданцы
5.00
рейтинг книги
Ох уж этот Мин Джин Хо 2

Энфис 6

Кронос Александр
6. Эрра
Фантастика:
героическая фантастика
рпг
аниме
5.00
рейтинг книги
Энфис 6