- •4.9.1. Изменяемость
- •4.9.2. Классы операций
- •98 Глава 4
- •4.9.3. Полнота
- •100 Глава 4
- •4.9.5. Операции egual, similar и copy
- •102 Глава 4
- •104 Глава 4
- •5. Исключительные ситуации
- •108 Глава 5
- •110 Глава 5
- •6.2.1. Сигнализация об исключительных ситуациях
- •5.2.2. Обработка исключительных ситуаций
- •112 Глава 5
- •5.2.3. Предложение resignal
- •6.2.4. Необрабатываемые исключительные ситуации
- •114 Глава 5
- •6.2.3. Предложение resignal
- •5.2.4. Необрабатываемые исключительные ситуации
- •116 Глава 5
- •118 Глава 5
- •118 Глава 5
- •120 Глава 5
- •122 Глава 5
- •124 Глава 5
- •128 Глава 6
- •130 Глава 6
- •6.2.1. Реализация итераторов
- •6.2.2. Использование итераторов
- •132 Глава 6
- •134 Глава 6
- •136 Глава 6
- •138 Глава 6
- •140 Глава 7
- •142 Глава 7
- •7.2. Абстракция данных
- •144 Глава 7
- •146 Глава 7
- •148 Глава 7
- •150 Глава 7
- •7.4. Генераторы
- •162 Глава 7
- •154 Глава 7
- •156 Глава 7
- •162 Глава 8
- •164 Глава 8
- •166 Глава 8
- •168 Глава 8
- •170 Глава 9
- •172 Глава 9
- •174 Глава 9
- •176 Глава 9
- •9.1.3. Пример
- •178 Глава 9
- •180 Глава 9
- •182 Глава 9
- •184 Глава 9
- •186 Глава 9
- •188 Глава 9
- •190 Глава 9
- •192 Глава. 9
- •194 Глава 9
188 Глава 9
ирование и отладка
while high^>low do
if s [lowF^" = s [high] then return (false) end low := low+ I
if high >> low + I then high :== high — I end end return (true) end palindrome
Эта реализация работает неверно с палиндромами, содержащими нечетное число символов, которые при этом имеют длину более одного символа. Следовательно, мы должны проверить ее со строкой «ere». Предположим, что в начале инициализации мы ожидаем, что переменные low и high равны значениям верхней и нижней границ массива и что после каждой итерации значение переменной low возрастает, а переменной high — уменьшается. В конце инициализации low == 1 и high == 3, как и ожидалось. Однако в конце первой итерации мы замечаем, что low = 2, a high == 3, чего не должно быть. В этом месте мы должны суметь обнаружить ошибку.
Если у вас есть доступ к .хорошему отладчику, то анализировать промежуточные результаты относительно легко, например, сообщая отладчику, трассировку каких переменных вы хотите осуществить. Если это не так, то имеет смысл написать значительный объем программ, единственная цель которых — помочь вам при анализе промежуточных результатов. В любом случае для каждого из типов должна быть написана программа, реализующая отображение объектов в абстрактной форме. Например, при отладке полиномов гораздо легче понять, что происходит, если полипом отображается в виде строки
"3+х**5" а не массива II: 3,0,0,0,1]
Эта программа может вызываться либо пользователем интерактивного отладчика, либо оператором print. Также полезно иметь обратную программу, принимающую на входе абстрактное представление объекта и выдающую соответствующий объект нужного типа. (В языке CLU мы придерживаемся соглашения, по которому процедура, подготавливающая данные для последующего отображения их на терминале, называется распаковкой, а обратная ей — упаковкой.)
При планировании сеансов отладки помните, что ошибка, вероятнее всего, находится не в том месте, в котором вам кажется. Если бы это было так, то вы бы ее уже нашли. Не следует цепляться за какое-либо фиксированное предположение о том, где расположена ошибка. Первое свидетельство о наличии ошибки может проявиться в месте, весьма далеком от ее реального место-
рождения. Если вам кажется, что вы знаете, какая из процедур держит ошибку, и вы уже потратили значительное количество ямени на анализ этой процедуры, то вероятнее всего, что вы абаетесь. Не замыкайтесь на чем-либо одном. Проанализируйте д мыслей, который привел вас к данной процедуре, и спросите бя, не просмотрели ли вы чего-либо.
1 Существует еще один подход к проблеме обнаружения ошибки, „ключающийся в выделении частей программы без ошибок. праздо легче выделить те места, где ошибки скорее всего отсут-»уют. Часто попытка продемонстрировать, что в некотором Jecre программы ошибка скорее всего отсутствует, приводит ^обнаружению ее именно в этом месте. В любом случае последо-ттельное исключение возможных мест ошибки часто является 1илучшим способом ее обнаружения.
В попытке сокращения числа возможных мест ошибки обра-.айте тщательное внимание как на программу, так и на входные анные. Каждый программист тратил время на обнаружение ,шибки, в то время как проблема заключалась во входных данных. ^ак уже говорилось, вы должны писать драйверы и заглушки пень аккуратно, избегая по возможности все вероятные ошибки. Внимательный анализ входных данных является хорошей демонстрацией принципа «начинайте с простого». Большинство "пибок довольно грубы. К простым, наиболее часто встреча-щимся ошибкам относятся следующие:
1. Перемена порядка следования входных аргументов.
2. Отсутствие инициализации переменной.
3. Отсутствие повторной инициализации переменной при по-1 игорном прохождении сегмента программы. 1. 4. Копирование только верхнего уровня структуры данных 1;вместо предполагаемого полного. 1 5. Ошибки при расстановке скобок в выражениях. 1 Помните, что рассуждения в процессе создания программы ^отличны от рассуждений при ее отладке. Наличие ошибки яв-„ляется свидетельством того, что ваш ход мыслей оказался оши-..бочным. Легко убедить себя в том, что процедура не содержит .ошибки, используя те же рассуждения, которые привели к ее ; появлению. В таком случае полезно обратиться к кому-либо за помощью. Обращение за помощью не является свидетельством •поражения. Напротив, это считается хорошим приемом. Попытайтесь объяснить свою проблему кому-нибудь еще. Очень , часто лишь одна попытка объяснить кому-либо ход своих мыслей позволяет обнаружить источник ошибки. Если этого и не произойдет, то услышанная новая точка зрения почти наверняка предотвратит вас от дальнейших заблуждений.
Одна из труднейших проблем заключается в решении о том, ^что считать само собой разумеющимся. Наивно полагать, что само
