Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка ПИ_ИКТ Программирование по С++ (1 семестр) _Хотов.docx
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
5.83 Mб
Скачать

Программа дает неверные результаты

Эта ситуация встречается чаще всего. Она может возникнуть по самым раз­ным причинам. К ней могут привести и простая ошибка в наборе текста программы, и неверный алгоритм решения задачи. Например, вы можете случайно исказить оператор присваивания:

double х = 3.45 * а[к - 1] + 2.5 * а[к + 1];

и написать, поставив вместо десятичной точки звездочку: double х = 3.45 * а[к - 1] + 2*5 * а[к + 1];

Из-за этой мало заметной ошибки значение переменной х изменится в четыре раза.

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

Гораздо чаще для обнаружения ошибки в программу устанавливаются кон­трольные точки (breakpoints), в те места, где ошибки наиболее вероятны. Программа останавливается на каждой контрольной точке. После останова можно просмотреть значения переменных и продолжить выполнение про­граммы до следующей контрольной точки. Многие инструментальные сред­ства программирования позволяют даже изменить переменные в контроль­ной точке и продолжить выполнение программы с другими значениями.

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

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

Программа дает правдоподобные результаты

Это самая коварная ситуация. Получив результаты, близкие к предполагае­мым, вы можете подумать, что программа работает правильно, и передать ее в эксплуатацию.

Как убедиться в том, что результаты правильны, а не правдоподобны? Здесь помогает тестирование программы. Тщательно подобранные тесты позволят отличить правдоподобные значения от правильных результатов. Как прави­ло, одного набора тестов недостаточно для убедительного доказательства неверности работы программы. Специалисты-тестировщики всегда подби­рают несколько наборов тестов так, чтобы точнее выявить дефекты про­граммы.

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

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

Локализация ошибки

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

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

Когда и прокрутка не помогает, приходится проверять логику выполнения программы. Проверка начинается с места обнаружения ошибки. Просмат­ривается полученная в этой точке отладочная печать, и проводятся рассуж­дения вроде следующих: "Такие результаты мог дать оператор А или опера­тор В. Но оператор В в этом случае не может выполняться. Значит, посмотрим на оператор А. Оператор А дал значение С, а оно могло полу­читься только в ситуации D. Чтобы возникла ситуация D, надо, чтобы...". На каждом логическом шаге приходится делать отладочную печать и не­большую прокрутку. Привлечение логических рассуждений помогает быст­рее проделать эту трудную работу, поскольку концентрирует внимание только на тех переменных, которые могут получить ошибочные значения, а таких переменных немного.

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