Логические ошибки в программе устранимы при

Сборник тестовых вопросов по информатике 9 класс

Правильный вариант ответа отмечен знаком +

1. Информатика (более полно, точно) – наука, изучающая:

— компьютеры

+ информационные системы и среды

— программирование

2. У алгоритма есть свойство:

+ массовости

— измеримости

— неотрицательности

3. По санитарно-гигиеническим нормам работа учеников 9 класса в компьютерном классе должна продолжаться не более:

— 1 часа без перерыва

+ 4 часов с двумя 10-минутными перерывами

— 6 часов с шестью 10-минутными перерывами

4. Более правильный вариант установки компьютера на столе (расстояние от экрана до глаз — Г, размеры свободной поверхности стола — П, положение системного блока — Б, пол или стол) – это:

— Г — 1,0 м, П — 0,51,0 м, Б — стол

+ Г — 0,6 м, П — 0,6´1,0 м, Б — пол

— Г — 0,5 м, П — 0,6´1,5 м, Б — стол

5. Наиболее правильный с точки зрения санитарно-гигиенических норм вариант цветового оформления страниц электронного учебника:

— фон экрана – красный, шрифт — синий

+ фон экрана – серый, шрифт — белый

— фон экрана – синий, шрифт — черный

6. Наиболее приемлема топология (расстановка) компьютеров в компьютерном классе:

— П-образная, компьютер учителя «внутри буквы П»

+ П-образная, компьютер учителя «в середине основания буквы П»

— П-образная, компьютер учителя у входа в класс

7. Математическая модель всегда представляется:

— лишь математическими уравнениями

— лишь математическими и геометрическими связями

+ любым математическим и геометрическим аппаратом

8. Компьютер как инструмент моделирования может использоваться:

— лишь для решения старых задач компьютерными средствами

— лишь для постановки и решения новых («компьютерных») задач

+ постановки и исследования новых и старых задач

9. Вопросу при компьютерном моделировании по схеме «исследуемая система – ? – алгоритм» соответствует:

— компьютер

— программа

+ модель

тест 10. Математическая модель оригинала (объекта, процесса) – это:

— любые математические уравнения, относящиеся к оригиналу

+ математическое описание связей и отношений в оригинал

— математическое именование, обозначение оригинал

11. Математическая модель используется, в основном, для:

— управления оригиналом

— изучения оригинала

+ управления и изучения оригинала

12. Вопросу при компьютерном моделировании по схеме «алгоритм – ? – пользователь» соответствует:

+ компьютер

— система

— модель

13. Математическая модель не зависит от:

— предположений о поведении оригинала

— методов изучения оригинала

+ используемых обозначений

14. Математическая модель системы должна всегда быть:

— в виде одного уравнения

+ адекватной

— универсальной (на все случаи)

15. Вопросу при компьютерном моделировании по схеме «модель – ? – компьютер» соответствует:

+ программа

— технология

— тест

16. Любая модель должна быть (в рамках гипотезы моделирования):

— абсолютно точной

— идеальной

+ адекватной

17. Математической моделью будет:

+ выражение для второго закона Ньютона

— словосочетание «треугольник»

— макет дома

18. Знаку вопроса в схеме компьютерного моделирования «модель – ? – программа» соответствует:

— компьютер

+ алгоритм

— тест

19. Компьютерная модель – модель, представленная:

+ компьютерными системами и программными средствами

— математическим языком

— большим объемом рутинных вычислений

тест-20. Математическая модель любой системы необходима, в основном, для:

+ познания

— быта

— производства

21. Соотношение вида точнее и грамотнее назвать моделью:

+ математической

— геометрической

— планиметрической

22. Основные риски безопасности сети – все перечисленное в списке:

— искажение, перекодировка и уменьшение информации

— техническое вмешательство, непрофессионализм администратора сети

+ искажение, утечка и потеря информации

23. В компьютерной сети необходимо реализовать все принципы, перечисленные в списке:
+ разделения обязанностей (привилегий) пользователей

— «все пользователи – равны по рангу»

— однотипных средств сети

24. К основному типу воздействия на компьютерную сеть относится:
— компьютерный сбой

+ логические закладки («мины»)

— аварийное отключение питания

25. При получении спама (e-mail с приложенным неизвестным файлом), следует:
— прочитать приложение и удалить, если оно не содержит ничего ценного

— сохранить в папке «Спам», затем выяснить IP-адрес генератора спама

+ удалить письмо с приложением, не раскрывая (не читая) его

26. Предоставляющий всем пользователям в сети свои ресурсы компьютер –

— пользовательский

— клиентский

+ сервер

27. Центральный компьютер сети – это:

— центральный процессор

+ сервер

— маршрутизатор

28. Интернет – глобальная…:

+ система (среда) сетей

— почтовый сервис

— компьютерная сеть

29. Основное назначение сети компьютеров –
+ удаленное использование сервера пользователями

— физическое соединение компьютеров для увеличения мощности сети

— совместное решение сложнейших задач пользователями сети

тест_30. Сеть в границах одного учреждения –

+ локальная

— глобальная

— Интранет

31. Маршрутизатор – устройство для соединения различных:

+ компьютерных сетей

— по архитектуре компьютеров

— маршрутов приема-передачи e-mail

32. Алгоритм не имеет свойства:

— полноты

— детерминированности

+ открытости

33. Метод реализации алгоритма сборкой из базовых команд —

— нисходящий

+ восходящий

— разбивающий

34. Логические (алгоритмические) ошибки в программе устранимы:

— лишь при отладке и тестировании

— лишь при сопровождении

+ во время отладки, тестирования и сопровождения

35. Число тестов для любого алгоритма:

— равно не менее 5

— чем больше, тем лучше

+ зависит от метода

36. По убыванию старшинства операции ранжирован список:

+ умножение и деление; сложение и вычитание

— умножение; деление; сложение; вычитание

— сложение; умножение; вычитание; деление

37. В программе на Паскале (Бейсике, Си) можно описывать

+ используемый тип данных

— используемый интерфейс

— часто встречающиеся ошибки

38. Фрагмент программы (дан на трех языках):

ШАЯ: y:=0; x:=12345; нц для i=1 до 4; y:=y+mod(х,10); x:=int(x/10); кц;

Паскаль: y:=0; x:=12345; for i:=1 to 4 do begin y:=y+x mod 10; x:=int(x/10) end;

Бейсик: y=0 : x=12345 : for :=1 to 4; y=y+x mod 10; x=int(x/10); next i;

вычисляет значение y равное

— 18

— 16

+ 14

39. Фрагмент

ШАЯ: нц для i от 1 до n; y:=mod(x,10); x:=div(x,10); кц

Паскаль: for i:=1 to n do begin y:=x mod 10; x:=x div 10 end

Бейсик: for i=1 to n : y= x mod 10 : x = x 10 : next i

вычисляет значение переменной y равное:

— цифре единиц натурального числа x

— цифре самого старшего разряда числа

+ цифре n-го разряда числа x (начиная с младшего разряда)

тест*40. Тело цикла

i:=1;s:=0; while i mod i=1 do begin if (x[i] div 5=0) then s:=s+x[i]; i:=i+1 end

— бесконечно выполняется (зацикливается)

+ ни разу не выполняется

— выполняется только при четных i

41. Фрагмент программы

i:=1; s:=0; while i<5 do begin x[i]:=i; if 2*trunc(x[i]/2)=x[i] then s:=s+i; i:=i+1

end; write(s);

выводит значение:

+ 6

— 10

— 11

42. Выделить в электронной таблице группу из 4 ячеек можно диапазоном:

+ A1 : D1

— A1 : B2

— A1 : C2

43. FrontPage – приложение для:

— редактирования графики, фото

— поиска интернет-ресурсов

+ создания веб-страниц

44. Для фрагмента электронной таблицы:

 

A

B

C

D

1

 

=$A$1*B1

   

2

       

3

       

При копировании формулы из ячейки В1 в ячейку D3, формула в ячейке D3 имеет вид:

+ =$A$1*D3

— =$A$1*B2

— =$A$1*B1

Получив приказ
исполнить алгоритм, компьютер выполняет
следующие действия:

  1. Находит в памяти
    алгоритм с указанным именем.

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

  3. Последовательно
    читает команды после строки нач
    и передает
    их исполнителю. Каждый такой приказ на
    выполнение команды называется вызовом
    этой команды.

  4. Встретив строку
    кон,
    проверяет,
    достигнута ли цель алгоритма, указанная
    в строке надо
    (см. примечание
    к п. 2).

  5. Заканчивает
    выполнение алгоритма.

Пример.
Компьютер
получает приказ исполнить алгоритм
«ход конем».

  1. Компьютер находит
    в памяти алгоритм А1.

  2. В строке дано
    записан
    комментарий — компьютер его пропускает.

  3. Компьютер
    последовательно командует Роботу
    вправо,
    вправо, вниз
    .
    Робот
    исполняет
    эти команды.

  4. В строке надо
    помещен
    комментарий — компьютер его пропускает.

  5. Компьютер
    заканчивает выполнение алгоритма «ход
    конем».

7.6. Ошибки в алгоритмах

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

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

Иногда логическая
ошибка может привести к отказу
— невозможности
выполнить очередную команду. Например,
при попытке выполнить алгоритм «ход
конем» (А1) в обстановке, изображенной
на рисунке 2, компьютер попытается
последовательно вызвать команды вправо,
вправо, вниз
.
Однако вторую команду вправо
Робот выполнить
не сможет — возникает отказ. Получив
от исполнителя сигнал отказа, компьютер
сообщает об ошибке и прекращает выполнение
алгоритма.

Рис. 2

У каждого исполнителя
могут быть свои причины отказов. Отказ
Робота
возникает
при попытке идти сквозь стену.

Ошибки в алгоритме
не всегда приводят к отказам. Возможны
логические ошибки, не обнаруживаемые
компьютером ни до, ни во время выполнения
алгоритма. Так, если в алгоритме А1 мы
вместо вправо
случайно напишем влево,
то компьютер выполнит алгоритм, Робот
из клетки А
переместится в клетку В (см. рис. 2), но
никаких сообщений об ошибках мы не
получим (да и откуда компьютеру знать,
куда мы на самом деле хотели переместить
Робота!).

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

Таблица 1. Ошибки
в алгоритмах.

Смысл ошибки

Название

Пример

1

Цель не достигнута

Логическая

Робот не попал
куда надо

2

Команда не входит
в СКИ

Синтаксическая

наверх, направо

3

Авария при попытке
исполнения команды

Семантическая
(отказ)

Попытка пройти
сквозь стену

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]

  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #

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

Отладку программы начинают с составления плана тестирования. Такой план должен представлять себе любой программист. Составление плана опирается на понятие об источниках и характере ошибок. Основными источниками ошибок являются недостаточно глубокая проработка математической модели или алгоритма решения задачи; нарушение соответствия между схемой алгоритма или записью его на алгоритмическом языке и программой, записанной на языке программирования; неверное представление исходных данных на программном бланке; невнимательность при наборе программы и исходных данных на клавиатуре устройства ввода.

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

Учитывая разнообразие источников ошибок, при составлении плана тестирования классифицируют ошибки на два типа: 1 – синтаксические; 2 – семантические (смысловые).

Синтаксические ошибки – это ошибки в записи конструкций языка программирования (чисел, переменных, функций, выражений, операторов, меток, подпрограмм).

Семантические ошибки – это ошибки, связанные с неправильным содержанием действий и использованием недопустимых значений величин.

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

В план тестирования обычно входят следующие этапы:

  1. Сравнение программы со схемой алгоритма.
  2. Визуальный контроль программы на экране дисплея или визуальное изучение распечатки программы и сравнение ее с оригиналом на программном бланке. Первые два этапа тестирования способны устранить больше количество ошибок, как синтаксических (что не так важно), так и семантических (что очень важно, так как позволяет исключить их трудоемкий поиск в процессе дальнейшей отладки).
  3. Трансляция программы на машинных язык. На этом этапе выявляются синтаксические ошибки. Компиляторы с языков Си, Паскаль выдают диагностическое сообщение о синтаксических ошибках в листинге программы (листингом называется выходной документ транслятора, сопровождающий оттранслированную программу на машинном языке – объектный модуль).
  4. Редактирование внешних связей и компоновка программы. На этапе редактирования внешних связей программных модуле программа-редактор внешних связей, или компоновщик задач, обнаруживает такие синтаксические ошибки, как несоответствие числа параметров в описании подпрограммы и обращении к ней, вызов несуществующей стандартной программы. например, 51 H вместо 51 N, различные длины общего блока памяти в вызывающем и вызываемом модуле и ряд других ошибок.
  5. Выполнение программы. После устранения обнаруженных транслятором и редактором внешних связей (компоновщиком задач) синтаксических ошибок переходят к следующему этапу – выполнению программы на ЭВМ на машинном языке: программа загружается в оперативную память, в соответствие с программой вводятся исходные данные и начинается счет. Проявление ошибки в процессе вода исходных данных или в процессе счета приводит к прерыванию счета и выдаче диагностического сообщения рабочей программы. Проявление ошибки дает повод для выполнения отладочных действий; отсутствие же сообщений об ошибках не означает их отсутствия в программе. План тестирования включает при этом проверку правильности полученных результатов для каких-либо допустимых значений исходных данных.
  6. Тестирование программы. Если программа выполняется успешно, желательно завершить ее испытания тестированием при задании исходных данных, принимающих предельные для программы значения. а также выходящие за допустимые пределы значения на входе.

Контрольные примеры (тесты) – это специально подобранные задачи, результаты которых заранее известны или могут быть определены без существенных затрат.

Наиболее простые способы получения тестов:

  • Подбор исходных данных, для которых несложно определить результата вычислений вручную или расчетом на калькуляторе.
  • Использование результатов, полученных на других ЭВМ или по другим программам.
  • Использование знаний о физической природе процесса, параметры которого определяются, о требуемых и возможных свойствах рассчитываемой конструкции. Хотя точное решение задачи заранее известно, суждение о порядке величин позволяет с большой вероятностью оценить достоверность результатов.

Семантическая
отладка — это процесс нахождения и
исправления ошибок, связанных с
неправильным указанием логических
страниц данных.

Существует
3 способа отладки программы:

Пошаговая
отладка программ с заходом в подпрограммы;

Пошаговая
отладка программ с выполнением
подпрограммы как одного оператора;

Выполнение
программы до точки остановки.

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

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

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

Тестирование
— это динамический контроль программы,
т.е. проверка правильности программы
при ее выполнении на компьютере.

Каждому
программисту известно, сколько времени
и сил уходит на отладку и тестирование
программ. На этот этап приходится около
50% общей стоимости разработки программного
обеспечения. Но не каждый из разработчиков
программных средств может верно,
определить цель тестирования. Нередко
можно услышать, что тестирование — это
процесс выполнения программы с целью
обнаружения в ней ошибок. Но эта цель
недостижима: ни какое самое тщательное
тестирование не дает гарантии, что
программа не содержит ошибок. Другое
определение: это процесс выполнения
программы с целью обнаружения в ней
ошибок. Отсюда ясно, что “удачным”
тестом является такой, на котором
выполнение программы завершилось с
ошибкой. Напротив, “неудачным” можно
назвать тест, не позволивший выявить
ошибку в программе. Определение также
указывает на объективную трудность
тестирования: это деструктивный ( т.е.
обратный созидательному ) процесс.
Поскольку программирование — процесс
конструктивный, ясно, что большинству
разработчиков программных средств
сложно “переключиться” при тестировании
созданной ими продукции. Основные
принципы организации тестирования:

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

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

 по
тем же соображениям организация —
разработчик программного обеспечения
не должна “единолично ” его тестировать
(должны существовать организации,
специализирующиеся на тестировании
программных средств);

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

 необходимо
тщательно подбирать тест не только для
правильных (предусмотренных ) входных
данных, но и для неправильных
(непредусмотренных);

 при
анализе результатов каждого теста
необходимо проверять, не делает ли
программа того, что она не должна делать;

 следует
сохранять использованные тесты (для
повышения эффективности повторного
тестирования программы после ее
модификации или установки у заказчика);

 тестирования
не должно планироваться исходя из
предположения, что в программе не будут
обнаружены ошибки (в частности, следует
выделять для тестирования достаточные
временные и материальные ресурсы);

 следует
учитывать так называемый “принцип
скопления ошибок” : вероятность наличия
не обнаруженных ошибок в некоторой
части программы прямо пропорциональна
числу ошибок, уже обнаруженных в этой
части;

 следует
всегда помнить, что тестирование —
творческий процесс, а не относиться к
нему как к рутинному занятию.

Существует
два основных вида тестирования:
функциональное и структурное. При
функциональном тестировании программа
рассматривается как “черный ящик”
(то есть ее текст не используется).
Происходит проверка соответствия
поведения программы ее внешней
спецификации. Возможно ли при этом
полное тестирование программы? Очевидно,
что критерием полноты тестирования в
этом случае являлся бы перебор всех
возможных значений входных данных, что
невыполнимо.

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

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

тестирование
отдельных модулей;

совместное
тестирование модулей;

тестирование
функций программного комплекса (т.е.
поиск различий между разработанной
программой и ее внешней спецификацией
);

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

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

12.
Данные в языке Си: константы и переменные.
Скалярные типы данных. Модификаторы
типов.






13.
Данные числовых типов в языке Си:
объявление, характеристика, допустимые
операции, приведение типов. Пример
использования.

14.
Операции языка Си. Приоритет операций.
Оператор и операция присваивания в
языке операции, приведение типов. Пример
использования.





Оператор
присваивания может присутствовать в
любом выражении языка С[1].
Этим С отличается от большинства других
языков программирования (Pascal, BASIC и
FORTRAN), в которых присваивание возможно
только в отдельном операторе. Общая
форма оператора присваивания:

имя_переменной=выражение;

Выражение
может быть просто константой или сколь
угодно сложным выражением. В отличие
от Pascal или Modula-2, в которых для присваивания
используется знак «:=», в языке С
оператором присваивания служит
единственный знак присваивания
«=». Адресатом(получателем),
т.е. левой частью оператора присваивания
должен быть объект, способный получить
значение, например, переменная.

В
книгах по С и в сообщениях компилятора
часто встречаются термины lvalue[2] (left
side value
)
и rvalue[3] (right
side value
).
Попросту говоря, lvalue —
это объект. Если этот объект может
стоять в левой части присваивания, то
он называется такжемодифицируемым (modifiablelvalue.
Подытожим сказанное: lvalue —
это объект в левой части оператора
присваивания, получающий значение,
чаще всего этим объектом является
переменная. Термин rvalue означает
значение выражения в правой части
оператора присваивания.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]

  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #

Проверка синтаксической и логической правильности программы, а также определение того, что программа функционирует на всем диапазоне допустимых данных, осуществляется на этапе …

 отладки


Решение:
Одним из этапов решения задачи на компьютере является отладка программы. Его цель – проверка синтаксической и логической правильности программы, а также определение того, что программа функционирует на всем диапазоне допустимых данных.
В процессе отладки программы выделяются следующие этапы:
1) трансляция исходного текста программы;
2) компоновка программы;
3) выполнение программы с целью определения логических ошибок;
4) тестирование программы.

Аннотация: Лекция носит факультативный характер. Здесь мы рассматриваем виды допускаемых в программировании ошибок, способы тестирования и отладки программ, инструменты встроенного отладчика.

Цель лекции

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

Тестирование и отладка программы

Чем больше опыта имеет программист, тем меньше ошибок в коде он совершает. Но, хотите верьте, хотите нет, даже самый опытный программист всё же допускает ошибки. И любая современная среда разработки программ должна иметь собственные инструменты для отладки приложений, а также для своевременного обнаружения и исправления возможных ошибок. Программные ошибки на программистском сленге называют багами (англ. bug — жук), а программы отладки кода — дебаггерами (англ. debugger — отладчик). Lazarus, как современная среда разработки приложений, имеет собственный встроенный отладчик, работу с которым мы разберем на этой лекции.

Ошибки, которые может допустить программист, условно делятся на три группы:

  1. Синтаксические
  2. Времени выполнения (run-time errors)
  3. Алгоритмические

Синтаксические ошибки

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

Найденная компилятором синтаксическая ошибка - нет объявления переменной i

Рис.
27.1.
Найденная компилятором синтаксическая ошибка — нет объявления переменной i

Подобные ошибки могут возникнуть при неправильном написании директивы или имени функции (процедуры); при попытке обратиться к переменной или константе, которую не объявляли (
рис.
27.1); при попытке вызвать функцию (процедуру, переменную, константу) из модуля, который не был подключен в разделе uses; при других аналогичных недосмотрах программиста.

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

Ошибки времени выполнения

Ошибки времени выполнения (run-time errors) тоже, как правило, легко устранимы. Они обычно проявляются уже при первых запусках программы, или во время тестирования. Если такую программу запустить из среды Lazarus, то она скомпилируется, но при попытке загрузки, или в момент совершения ошибки, приостановит свою работу, выведя на экран соответствующее сообщение. Например, такое:

Сообщение Lazarus об ошибке времени выполнения

Рис.
27.2.
Сообщение Lazarus об ошибке времени выполнения

В данном случае программа при загрузке должна была считать в память отсутствующий текстовый файл MyFile.txt. Поскольку программа вызвала ошибку, она не запустилась, но в среде Lazarus процесс отладки продолжается, о чем свидетельствует сообщение в скобках в заголовке главного меню, после названия проекта. Программисту в подобных случаях нужно сбросить отладчик командой меню «Запуск -> Сбросить отладчик«, после чего можно продолжить работу над проектом.

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

Если программу запустить из самой Windows, при возникновении этой ошибки появится такое же сообщение. При этом если нажать «OK«, программа даже может запуститься, но корректно работать все равно не будет.

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

begin
  MySL:= TStringList.Create;
  MySL.Add('Новая строка');
end;
    

В данном примере программист допустил типичную для начинающих ошибку — не освободил класс TStringList. Это не приведет к сбою или аварийному завершению программы, но в итоге можно бесполезно израсходовать очень много памяти. Конечно, эта память будет освобождена после выгрузки программы (за этим следит операционная система), но утечка памяти во время выполнения программы тоже может привести к неприятным последствиям, потребляя все больше и больше ресурсов и излишне нагружая процессор. В подобных случаях после работы с объектом программисту нужно не забывать освобождать память:

begin
  MySL:= TStringList.Create;
  MySL.Add('Новая строка');
  ...; //работа с объектом
  MySL.Free; //освободили объект
end;
    

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

begin
  try
    MySL:= TStringList.Create;
    MySL.Add('Новая строка');
    ...; //работа с объектом
  finally
    MySL.Free; //освободили объект, даже если была ошибка
  end;
end;
    

Итак, во избежание ошибок времени выполнения программист должен не забывать делать проверку на правильность ввода пользователем допустимых значений, заключать опасный код в блоки try…finally…end или try…except…end, делать проверку на существование открываемого файла функцией FileExists и вообще соблюдать предусмотрительность во всех слабых местах программы. Не полагайтесь на пользователя, ведь недаром говорят, что если в программе можно допустить ошибку, пользователь эту возможность непременно найдет.

Алгоритмические ошибки

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

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

Если программа работает правильно с одними наборами исходных данных, и неправильно с другими, то это свидетельствует о наличии алгоритмической ошибки. Алгоритмические ошибки иногда называют логическими, обычно они связаны с неверной реализацией алгоритма программы: вместо «+» ошибочно поставили «-«, вместо «/» — «*», вместо деления значения на 0,01 разделили на 0,001 и т.п. Такие ошибки обычно не обнаруживаются во время компиляции, программа нормально запускается, работает, а при анализе выводимого результата выясняется, что он неверный. При этом компилятор не укажет программисту на ошибку — чтобы найти и устранить её, приходится анализировать код, пошагово «прокручивать» его выполнение, следя за результатом. Такой процесс называется отладкой.

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

Как искать и исправлять ошибки в коде

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

Шаг 1: Занесите ошибку в трекер

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

  1. Вы забыли какую-то важную деталь об ошибке, например, в чем она заключалась.
  2. Вы могли делегировать ее кому-то более опытному.

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

Вы должны записать в трекер следующую информацию:

  1. Что делал пользователь.
  2. Что он ожидал увидеть.
  3. Что случилось на самом деле.

Это должно подсказать, как воспроизвести ошибку. Если вы не сможете воспроизвести ее в любое время, ваши шансы исправить ошибку стремятся к нулю.

Шаг 2: Поищите сообщение об ошибке в сети

Если у вас есть сообщение об ошибке, то вам повезло. Или оно будет достаточно информативным, чтобы вы поняли, где и в чем заключается ошибка, или у вас будет готовый запрос для поиска в сети. Не повезло? Тогда переходите к следующему шагу.

Шаг 3: Найдите строку, в которой проявляется ошибка

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

Шаг 4: Найдите точную строку, в которой появилась ошибка

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

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

Шаг 5: Выясните природу ошибки

Ошибки могут проявлять себя по-разному, но большинство из них можно отнести к той или иной категории. Вот наиболее частые.

    Вы начали цикл for с единицы вместо нуля или наоборот. Или, например, подумали, что метод .count() или .length() вернул индекс последнего элемента. Проверьте документацию к языку, чтобы убедиться, что нумерация массивов начинается с нуля или с единицы. Эта ошибка иногда проявляется в виде исключения Index out of range .
    Ваш процесс или поток пытается использовать результат выполнения дочернего до того, как тот завершил свою работу. Ищите использование sleep() в коде. Возможно, на мощной машине дочерний поток выполняется за миллисекунду, а на менее производительной системе происходят задержки. Используйте правильные способы синхронизации многопоточного кода: мьютексы, семафоры, события и т. д.

  1. Неправильные настройки или константы
    Проверьте ваши конфигурационные файлы и константы. Я однажды потратил ужасные 16 часов, пытаясь понять, почему корзина на сайте с покупками виснет на стадии отправки заказа. Причина оказалась в неправильном значении в /etc/hosts , которое не позволяло приложению найти ip-адрес почтового сервера, что вызывало бесконечный цикл в попытке отправить счет заказчику.
  2. Неожиданный null
    Бьюсь об заклад, вы не раз получали ошибку с неинициализированной переменной. Убедитесь, что вы проверяете ссылки на null , особенно при обращении к свойствам по цепочке. Также проверьте случаи, когда возвращаемое из базы данных значение NULL представлено особым типом.
  3. Некорректные входные данные
    Вы проверяете вводимые данные? Вы точно не пытаетесь провести арифметические операции с введенными пользователем строками?
  4. Присваивание вместо сравнения
    Убедитесь, что вы не написали = вместо == , особенно в C-подобных языках.
  5. Ошибка округления
    Это случается, когда вы используете целое вместо Decimal , или float для денежных сумм, или слишком короткое целое (например, пытаетесь записать число большее, чем 2147483647, в 32-битное целое). Кроме того, может случиться так, что ошибка округления проявляется не сразу, а накапливается со временем (т. н. Эффект бабочки).
  6. Переполнение буфера и выход за пределы массива
    Проблема номер один в компьютерной безопасности. Вы выделяете память меньшего объема, чем записываемые туда данные. Или пытаетесь обратиться к элементу за пределами массива.
  7. Программисты не умеют считать
    Вы используете некорректную формулу. Проверьте, что вы не используете целочисленное деление вместо взятия остатка, или знаете, как перевести рациональную дробь в десятичную и т. д.
  8. Конкатенация строки и числа
    Вы ожидаете конкатенации двух строк, но одно из значений — число, и компилятор пытается произвести арифметические вычисления. Попробуйте явно приводить каждое значение к строке.
  9. 33 символа в varchar(32)
    Проверяйте данные, передаваемые в INSERT , на совпадение типов. Некоторые БД выбрасывают исключения (как и должны делать), некоторые просто обрезают строку (как MySQL). Недавно я столкнулся с такой ошибкой: программист забыл убрать кавычки из строки перед вставкой в базу данных, и длина строки превысила допустимую как раз на два символа. На поиск бага ушло много времени, потому что заметить две маленькие кавычки было сложно.
  10. Некорректное состояние
    Вы пытаетесь выполнить запрос при закрытом соединении или пытаетесь вставить запись в таблицу прежде, чем обновили таблицы, от которых она зависит.
  11. Особенности вашей системы, которых нет у пользователя
    Например: в тестовой БД между ID заказа и адресом отношение 1:1, и вы программировали, исходя из этого предположения. Но в работе выясняется, что заказы могут отправляться на один и тот же адрес, и, таким образом, у вас отношение 1:многим.

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

Шаг 6: Метод исключения

Если вы не можете найти строку с ошибкой, попробуйте или отключать (комментировать) блоки кода до тех пор, пока ошибка не пропадет, или, используя фреймворк для юнит-тестов, изолируйте отдельные методы и вызывайте их с теми же параметрами, что и в реальном коде.

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

Шаг 7: Логгируйте все подряд и анализируйте журнал

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

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

Шаг 8: Исключите влияние железа или платформы

Замените оперативную память, жесткие диски, поменяйте сервер или рабочую станцию. Установите обновления, удалите обновления. Если ошибка пропадет, то причиной было железо, ОС или среда. Вы можете по желанию попробовать этот шаг раньше, так как неполадки в железе часто маскируют ошибки в ПО.

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

Ради интереса, переключите кабель питания в другую розетку или к другому ИБП. Безумно? Почему бы не попробовать?

Если у вас возникает одна и та же ошибка вне зависимости от среды, то она в вашем коде.

Шаг 9: Обратите внимание на совпадения

  1. Ошибка появляется всегда в одно и то же время? Проверьте задачи, выполняющиеся по расписанию.
  2. Ошибка всегда проявляется вместе с чем-то еще, насколько абсурдной ни была бы эта связь? Обращайте внимание на каждую деталь. На каждую. Например, проявляется ли ошибка, когда включен кондиционер? Возможно, из-за этого падает напряжение в сети, что вызывает странные эффекты в железе.
  3. Есть ли что-то общее у пользователей программы, даже не связанное с ПО? Например, географическое положение (так был найден легендарный баг с письмом за 500 миль).
  4. Ошибка проявляется, когда другой процесс забирает достаточно большое количество памяти или ресурсов процессора? (Я однажды нашел в этом причину раздражающей проблемы «no trusted connection» с SQL-сервером).

Шаг 10: Обратитесь в техподдержку

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

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

Полезные советы (когда ничего не помогает)

  1. Позовите кого-нибудь еще.
    Попросите коллегу поискать ошибку вместе с вами. Возможно, он заметит что-то, что вы упустили. Это можно сделать на любом этапе.
  2. Внимательно просмотрите код.
    Я часто нахожу ошибку, просто спокойно просматривая код с начала и прокручивая его в голове.
  3. Рассмотрите случаи, когда код работает, и сравните их с неработающими.
    Недавно я обнаружил ошибку, заключавшуюся в том, что когда вводимые данные в XML-формате содержали строку xsi:type=’xs:string’ , все ломалось, но если этой строки не было, все работало корректно. Оказалось, что дополнительный атрибут ломал механизм десериализации.
  4. Идите спать.
    Не бойтесь идти домой до того, как исправите ошибку. Ваши способности обратно пропорциональны вашей усталости. Вы просто потратите время и измотаете себя.
  5. Сделайте творческий перерыв.
    Творческий перерыв — это когда вы отвлекаетесь от задачи и переключаете внимание на другие вещи. Вы, возможно, замечали, что лучшие идеи приходят в голову в душе или по пути домой. Смена контекста иногда помогает. Сходите пообедать, посмотрите фильм, полистайте интернет или займитесь другой проблемой.
  6. Закройте глаза на некоторые симптомы и сообщения и попробуйте сначала.
    Некоторые баги могут влиять друг на друга. Драйвер для dial-up соединения в Windows 95 мог сообщать, что канал занят, при том что вы могли отчетливо слышать звук соединяющегося модема. Если вам приходится держать в голове слишком много симптомов, попробуйте сконцентрироваться только на одном. Исправьте или найдите его причину и переходите к следующему.
  7. Поиграйте в доктора Хауса (только без Викодина).
    Соберите всех коллег, ходите по кабинету с тростью, пишите симптомы на доске и бросайте язвительные комментарии. Раз это работает в сериалах, почему бы не попробовать?

Что вам точно не поможет

  1. Паника
    Не надо сразу палить из пушки по воробьям. Некоторые менеджеры начинают паниковать и сразу откатываться, перезагружать сервера и т. п. в надежде, что что-нибудь из этого исправит проблему. Это никогда не работает. Кроме того, это создает еще больше хаоса и увеличивает время, необходимое для поиска ошибки. Делайте только один шаг за раз. Изучите результат. Обдумайте его, а затем переходите к следующей гипотезе.
  2. «Хелп, плиииз!»
    Когда вы обращаетесь на форум за советом, вы как минимум должны уже выполнить шаг 3. Никто не захочет или не сможет вам помочь, если вы не предоставите подробное описание проблемы, включая информацию об ОС, железе и участок проблемного кода. Создавайте тему только тогда, когда можете все подробно описать, и придумайте информативное название для нее.
  3. Переход на личности
    Если вы думаете, что в ошибке виноват кто-то другой, постарайтесь по крайней мере говорить с ним вежливо. Оскорбления, крики и паника не помогут человеку решить проблему. Даже если у вас в команде не в почете демократия, крики и применение грубой силы не заставят исправления магическим образом появиться.

Ошибка, которую я недавно исправил

Это была загадочная проблема с дублирующимися именами генерируемых файлов. Дальнейшая проверка показала, что у файлов различное содержание. Это было странно, поскольку имена файлов включали дату и время создания в формате yyMMddhhmmss . Шаг 9, совпадения: первый файл был создан в полпятого утра, дубликат генерировался в полпятого вечера того же дня. Совпадение? Нет, поскольку hh в строке формата — это 12-часовой формат времени. Вот оно что! Поменял формат на yyMMddHHmmss , и ошибка исчезла.

Отладка

Отладка, или debugging, — это поиск (локализация), анализ и устранение ошибок в программном обеспечении, которые были найдены во время тестирования.

Виды ошибок

Ошибки компиляции

Это простые ошибки, которые в компилируемых языках программирования выявляет компилятор (программа, которая преобразует текст на языке программирования в набор машинных кодов). Если компилятор показывает несколько ошибок, отладку кода начинают с исправления самой первой, так как она может быть причиной других.

В интерпретируемых языках (например Python) текст программы команда за командой переводится в машинный код и сразу исполняется. К моменту обнаружения ошибки часть программы уже может исполниться.

Ошибки компоновки

Ошибки связаны с разрешением внешних ссылок. Выявляет компоновщик (редактор связей) при объединении модулей программы. Простой пример — ситуация, когда требуется обращение к подпрограмме другого модуля, но при компоновке она не найдена. Ошибки также просто найти и устранить.

Ошибки выполнения (RUNTIME Error)

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

  • сообщение об ошибке, которую зафиксировали схемы контроля машинных команд. Это может быть переполнение разрядной сетки (когда старшие разряды результата операции не помещаются в выделенной области памяти), «деление на ноль», нарушение адресации и другие;
  • сообщение об ошибке, которую зафиксировала операционная система. Она же, как правило, и документирует ошибку. Это нарушение защиты памяти, отсутствие файла с заданным именем, попытка записи на устройство, защищенное от записи;
  • прекращение работы компьютера или зависание. Это и простые ошибки, которые не требуют перезагрузки компьютера, и более сложные, когда нужно выключать ПК;
  • получение результатов, которые отличаются от ожидаемых. Программа работает стабильно, но выдает некорректный результат, который пользователь воспринимает за истину.

Ошибки выполнения можно разделить на три большие группы.

Ошибки определения данных или неверное определение исходных данных. Они могут появиться во время выполнения операций ввода-вывода.

К ним относятся:

  • ошибки преобразования;
  • ошибки данных;
  • ошибки перезаписи.

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

Логические ошибки. Они могут возникать из ошибок, которые были допущены при выборе методов, разработке алгоритмов, определении структуры данных, кодировании модуля.

В эту группу входят:

  • ошибки некорректного использования переменных. Сюда относятся неправильный выбор типов данных, использование индексов, выходящих за пределы определения массивов, использование переменных до присвоения переменной начального значения, нарушения соответствия типов данных;
  • ошибки вычислений. Это некорректная работа с переменными, неправильное преобразование типов данных в процессе вычислений;
  • ошибки взаимодействия модулей или межмодульного интерфейса. Это нарушение типов и последовательности при передаче параметров, области действия локальных и глобальных переменных, несоблюдение единства единиц измерения формальных и фактических параметров;
  • неправильная реализация логики при программировании.

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

Веб-разработчик с нуля

Освойте веб-разработку за 12 месяце и делайте сайты и приложения любой сложности.

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

Метод ручного тестирования

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

Метод индукции

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

Вот как выглядит процесс:

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

Метод дедукции

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

Метод обратного прослеживания

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

Как выполняется отладка в современных IDE

Ранние отладчики, например gdb, представляли собой отдельные программы с интерфейсами командной строки. Более поздние, например первые версии Turbo Debugger, были автономными, но имели собственный графический интерфейс для облегчения работы. Сейчас большинство IDE имеют встроенный отладчик. Он использует такой же интерфейс, как и редактор кода, поэтому можно выполнять отладку в той же среде, которая используется для написания кода.

Отладчик позволяет разработчику контролировать выполнение и проверять (или изменять) состояние программ. Например, можно использовать отладчик для построчного выполнения программы, проверяя по ходу значения переменных. Сравнение фактических и ожидаемых значений переменных или наблюдение за ходом выполнения кода может помочь в отслеживании логических (семантических) ошибок.

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

Шаг с заходом (step into)

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

Шаг с обходом (step over)

Команда также выполняет очередную инструкцию. Однако когда step into будет входить в вызовы функций и выполнять их строка за строкой, step over выполнит всю функцию, не останавливаясь, и вернет управление после ее выполнения. Команда step over позволяет пропустить функции, если разработчик уверен, что они уже исправлены, или не заинтересован в их отладке в данный момент.

Шаг с выходом (step out)

В отличие от step into и step over, step out выполняет не следующую строку кода, а весь оставшийся код функции, исполняемой в настоящее время. После возврата из функции он возвращает управление разработчику. Эта команда полезна, когда специалист случайно вошел в функцию, которую не нужно отлаживать.

Как правило, при пошаговом выполнении можно идти только вперед. Поэтому легко перешагнуть место, которое нужно проверить. Если это произошло, необходимо перезапустить отладку.

У некоторых отладчиков (таких как GDB 7.0, Visual Studio Enterprise Edition 15.5 и более поздних версий) есть возможность вернуться на шаг назад. Это полезно, если пропущена цель либо нужно повторно проверить выполненную инструкцию.

Веб-разработчик с нуля

За 12 месяцев вы освоите базовую верстку, frontend и backend. В конце обучения у вас будет готовое портфолио из проектов.

Виды ошибок в программах

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

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

Итак, основных вида всего три:

Синтаксические ошибки в программах

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

Синтаксические ошибки — это ошибки синтаксиса (а то бы вы не догадались))). То есть ошибки правил языка. Например, для Паскаля это будет синтаксической ошибкой:

Потому что после первой строки нет точки с запятой.

Подобные ошибки очень часто совершают новички. И это вгоняет их в ступор — они пугаются и не могут понять, что же не так с их кодом. Хотя если бы они внимательно его посмотрели и прочитали сообщение об ошибке, то легко могли бы исправить её:

Синтаксические ошибки в программах

Потому что в сообщении чётко сказано:

что можно перевести как

То есть компилятор говорит нам: я ожидал увидеть точку с запятой, а нашёл идентификатор READLN .

Логические ошибки в программах

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

И компилятор вам ничего об этой ошибке не расскажет, потому что правила языка не нарушены.

Поиски таких ошибок могут занять много времени и отнять у вас немало здоровья. Поэтому при разработке программ лучше не торопиться и стараться не допускать логических ошибок.

Пример логической ошибки:

Здесь мы сравниваем значение i с числом 15, и выводим сообщение, если i = 15 . Но фишка в том, что в данном цикле i не будет равно 15 НИКОГДА, потому что в цикле переменной i присваиваются значения от 1 до 10.

Эта ошибка довольно безобидная. Здесь мы имеем просто бессмысленный код, который не причинит никакого вреда. Однако представьте, что программа должна выдавать какой-то сигнал тревоги, если i = 15 . Тогда получится, что никакого сигнала пользователь никогда не услышит, даже если случилось что-то страшное. А всё потому, что программист немного ошибся. Вот так вот и падают ракеты и самолёты…

Распространённые логические ошибки в С++ вы можете посмотреть здесь.

Ошибки времени выполнения программы

Даже если исходный код не содержит ни логических, не синтаксических ошибок, это ещё не означает, что ваша программа безупречна. Потому что ошибки могут возникнуть в ходе выполнения программы. Например, случайно будет удалён файл, который должна читать программа, и она не сможет его найти. Если не принять мер, то программа может завершиться аварийно. А пользователям такое поведение программ очень не нравится.

Одна из самых рапространённых ошибок времени выполнения — это неожиданное деление на ноль. Пример:

Что здесь такого? Всё правильно и с точки зрения логики, и с точки зрения синтаксиса. И в большинстве случаев программа отработает без каких-либо неожиданностей.

Но представьте, что пользователь введёт ноль. Что тогда будет? Правильно — попытка деления на ноль. А на ноль делить нельзя. Поэтому во время выполнения этой программы произойдёт ошибка, которая очень расстроит пользователя. Потому что в случае, например, с консольным приложением программа просто закроется, и пользователь не поймёт, что это было. Но зато поймёт, что программа — говно, и программы от этого разработчика лучше больше никогда не использовать.

В данном случае, если вы не уверены на 100%, что y будет отличаться от нуля, надо всегда делать проверку на ноль. И хороший код должен быть хотя бы таким:

Ну что же. На этом с видами ошибок пока всё. Изучайте программирование и поменьше ошибайтесь.

Логические ошибки

Потому что в сообщении чётко сказано:

что можно перевести как

То есть компилятор говорит нам: я ожидал увидеть точку с запятой, а нашёл идентификатор READLN .

Логические ошибки в программах

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

И компилятор вам ничего об этой ошибке не расскажет, потому что правила языка не нарушены.

Поиски таких ошибок могут занять много времени и отнять у вас немало здоровья. Поэтому при разработке программ лучше не торопиться и стараться не допускать логических ошибок.

Пример логической ошибки:

Здесь мы сравниваем значение i с числом 15, и выводим сообщение, если i = 15 . Но фишка в том, что в данном цикле i не будет равно 15 НИКОГДА, потому что в цикле переменной i присваиваются значения от 1 до 10.

Эта ошибка довольно безобидная. Здесь мы имеем просто бессмысленный код, который не причинит никакого вреда. Однако представьте, что программа должна выдавать какой-то сигнал тревоги, если i = 15 . Тогда получится, что никакого сигнала пользователь никогда не услышит, даже если случилось что-то страшное. А всё потому, что программист немного ошибся. Вот так вот и падают ракеты и самолёты…

Распространённые логические ошибки в С++ вы можете посмотреть здесь.

Ошибки времени выполнения программы

Даже если исходный код не содержит ни логических, не синтаксических ошибок, это ещё не означает, что ваша программа безупречна. Потому что ошибки могут возникнуть в ходе выполнения программы. Например, случайно будет удалён файл, который должна читать программа, и она не сможет его найти. Если не принять мер, то программа может завершиться аварийно. А пользователям такое поведение программ очень не нравится.

Одна из самых рапространённых ошибок времени выполнения — это неожиданное деление на ноль. Пример:

Что здесь такого? Всё правильно и с точки зрения логики, и с точки зрения синтаксиса. И в большинстве случаев программа отработает без каких-либо неожиданностей.

Но представьте, что пользователь введёт ноль. Что тогда будет? Правильно — попытка деления на ноль. А на ноль делить нельзя. Поэтому во время выполнения этой программы произойдёт ошибка, которая очень расстроит пользователя. Потому что в случае, например, с консольным приложением программа просто закроется, и пользователь не поймёт, что это было. Но зато поймёт, что программа — говно, и программы от этого разработчика лучше больше никогда не использовать.

В данном случае, если вы не уверены на 100%, что y будет отличаться от нуля, надо всегда делать проверку на ноль. И хороший код должен быть хотя бы таким:

Ну что же. На этом с видами ошибок пока всё. Изучайте программирование и поменьше ошибайтесь.

Источник

Логические ошибки

Опытные программисты знают, что ошибки в программе делятся на два основных типа. Первая разновидность — это баги, которые вылавливаются при компиляции. К ним относятся преимущественно проблемы с синтаксисом, явная несовместимости типов и т.д. Эту разновидность багов исправляют на этапе разработки, так как компилятор «вылетает по ошибке». Их просто невозможно не заметить.

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

Выявить этот вид багов удается только на этапе тестирования. И хорошо, если ошибку удается исправить локальной «заплаткой». Нередко приходится менять практически весь алгоритм. А это – дополнительные затраты времени, сил, а в коммерческих проектах – финансовые, а иногда и репутационные потери.

Застраховаться полностью от логических ошибок невозможно. Но вполне реально изучить самые распространенные типы таких багов и проверять на них программу на самых ранних этапах.

Алгоритм – основа всех основ

Написание алгоритма – это самый первый этап разработки, когда идеи только обретают форму еще без привязки к языку программирования. Нередко начинающие программисты относятся к созданию алгоритма «спустя рукава» — делают только «общие наброски» или вообще приступают к кодингу сразу без предварительной проработки логики «на бумаге».

Такой подход возможен при решении учебных задач на 10-15 строк кода. Но при работе над серьезным программным продуктом пренебрежение алгоритмом – почти гарантированный путь к логическим ошибкам и катастрофическим результатам.

Как работать с алгоритмом:

  • Начинайте с малого. Запишите алгоритм упрощенно, в виде «черных ящиков» (логических блоков без подробностей их работы). Это поможет оценить работоспособность идеи в целом.
  • Двигайтесь сверху вниз. Сначала – общая идея «в целом», далее – детализация основных функций и так далее. Не бойтесь ставить «заглушки» и прорабатывать мелкие детали в последнюю очередь. Двигаться сверху вниз проще и с точки зрения логики, и психологически.
  • Пишите команды «от имени компьютера». Помните, что вы имеете дело не с человеком, а с компьютером, который буквально выполняет команды и после каждого шага ждет ответа на вопрос «что делать». Например, логический блок «сохранение документа» будет понятен вам, но не компьютеру. Он вполне подойдет на этапе крупных блоков в качестве заглушки. Но далее придется проработать все действия пошагово с учетом выбранного языка программирования.
  • Делите код на отдельные модули (блоки), которые можно будет запускать отдельно друг от друга. Это сильно облегчит как алгоритмизацию, так и процесс отладки.
  • Читайте алгоритм «как будто компьютер». Проверяйте себя на каждом этапе. Главное правило – одинаковые данные всегда должны вести к одинаковым результатам.

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

Что делать начинающим программистам

«Не туда положил»: о типах данных

Здесь проблемы возникают в двух случаях:

  1. При статической типизации в таких языках, как С++, Java или С# неверно определен тип переменной. Большинство подобных ошибок выявляет компилятор. Но здесь есть свои «лазейки» для багов. Например, в С# вполне возможно «положить» вещественное значение в целочисленную переменную. И оно просто округлится до целого. Т.е. вместо 1,3 у вас будет храниться значение 1. Само собой, все дальнейшие вычисления будут содержать ошибку.
  2. При динамической типизации (JavaScript, Python, PHP) неявное приведение типов – самое обычное дело. А потому здесь даже компилятор промолчит в случае ошибки. Например, вы планируете получить целочисленное значение, для чего отправляете результаты вычислений в переменную типа int. Но программа видит «знаки после запятой», и переменная без вашего участия меняет тип на float.

Самый известный пример подобной ошибки – деление двух целых чисел с остатком.

int a = 25;

int b = 8;

float c = a/b;

Console.Write(c);

Как вы думаете, какое число будет выведено на экран после выполнения последней строки? По идее, это должно быть 3,125. Но, например, в C# вы увидите целую цифру «3». Причем, тип переменной С будет float, как вы и заказывали.

Здесь проблема в другом: компилятор сначала проводит целочисленное деление, так как определяет переменные A и B как относящиеся к типу int. И полученный результат отправляет в переменную C (тип float). Целое значение (32 разряда) прекрасно помещается в 64-разрядный float, отведенный под хранение результата. Компилятор не видит ошибки. А у вас в программе появляются неточные вычисления, которые могут повлечь за собой большие проблемы.

Аналогичным образом компилятор округлит значение до целого и в Python 2. А уже в Python 3 алгоритм преобразования типов сработает иначе: сначала определится тип переменной, куда отправляется значение, а потом будет проводиться деление. После компиляции кода в Python 3 вы получите c=3,125.

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

Высвобождение ресурсов: до 100% загрузки процессора

Если вы работаете с языком, где реализована автоматическая сборка мусора, внимательно следите за тем, как происходит высвобождение ресурсов. В отдельных случаях эта полезная функция может начать работать во вред: отбирать для себя максимум памяти, загружать дополнительными задачами процессор, замедлять и даже «подвешивать» программу.

Например, в Java этот процесс работает так:

  • Виртуальная машина проводит поиск ненужных объектов;
  • Составляет из них очередь на удаление;
  • По мере продвижения очереди очищает ячейки памяти.

В результате очередь может стать настолько большой, что компьютер перестанет с ней справляться. А до удаления всех ненужных объектов дело может даже не дойти.

Как итог, программа «загрязняет» память служебной информацией. Кроме того, формируется уязвимость: в этой «свалке данных» могут оказаться логины с паролями и другие личные данные.

Намного надежнее своевременно применять функции типа try-with-resources и try-finally. И все ресурсы очищать в том коде, где вы их получили.

И еще: не забывайте закрывать сессии и файлы сразу после того, как они перестают быть нужны. Это должно быть также естественно, как закрыть скобку в коде.

Конфликт интересов

Конфликт потоков: кто первый успеет?

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

Например: первый поток в результате вычислений получает значение 1, отправляет его в переменную. В это время второй поток перехватывает доступ и обнуляет эту переменную. А первый – сохраняет значение. В результате вы планировали запомнить значение 1. А у вас сразу после вычислений сохраняется 0. И далее копятся ошибка за ошибкой.

Чтобы избежать этой проблемы не забывайте при работе с разными потоками ставить блокировки, чтобы они не обращались одновременно к одним и тем же ресурсам. Можно применять и другие методы синхронизации – события, семафоры, критические секции.

Переменные: склонность к глобализации

Эта ошибка популярна у новичков – стремление объявить сразу все переменные и сделать их глобальными. В результате таких действий вы:

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

На глобальном уровне определяют только необходимый минимум – те самые глобальные переменные, с которыми работают практически все модули. Все остальные объявляйте в тех модулях, где они работают. И не забывайте об идентификаторах ограничения доступа: public, private и protected.

Переполнение буфера в С/С++: «танцы на граблях»

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

Но нередко для экономии ресурсов программисты используют C-библиотеки. В этом случае очень важно следить за буферизацией. Дело в том, что языки C/С++ очень уязвимы к переполнению буфера. Если он окажется меньше, чем нужно для работы, программа попытается использовать память за пределами выделенного участка. Результат – многочисленные, можно сказать, легендарные ошибки, когда в обрабатываемые данные попадает «неведомый мусор».

Хуже того, это очень известная уязвимость. С 1988 года хакеры пользуются этой «дырой», чтобы подменить адрес возврата в стеке на собственный. Так в программу попадает подставная функция, которая передает управление коду мошенников.

Изучите особенности работы с буфером и методы борьбы с его переполнением, чтобы не пополнить число «танцующих на граблях с 30-летней историей».

Отладка и поиск логических багов

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

  • Пользуйтесь возможностями отладчика вашей IDE. Ставьте контрольные точки, отражайте на консоли ход выполнения и значения переменных, переходите в «пошаговый режим» выполнения в наиболее «подозрительных» участках кода. Так вы быстрее сможете локализовать проблему.
  • Помните: компилятор может неправильно указывать строку с ошибкой. Если вам повезло, и компилятор помог вам выявить баг, не спешите радоваться. При «завершении с ошибкой» вы видите номер строки, в которой выполнение программы стало невозможным. Если проблема в простейшей опечатке (синтаксис), то строка с багом вам известна. В случае логических ошибок вероятнее всего, проблема появилась на более ранних этапах работы программы. А в указанной строке была попытка использовать ошибочные данные, что и привело к аварийному завершению.
  • Старый добрый листинг программы тоже может помочь. Если вы запутались и не знаете, что делать, распечатайте код и попробуйте его «выполнить» как будто вы – и есть компьютер. Шаг за шагом двигайте по командам. Переходите от блока к блоку так, как это делает программа. На каждом этапе вычисляйте и фиксируйте значения переменных (калькулятором пользоваться можно). И сверяйте результаты с ожидаемыми. Все в порядке? Двигайтесь дальше. Что-то не так? Ура! Вы локализовали баг. Можно возвращаться за компьютер и разбираться подробнее в этом фрагменте кода в отладчике.

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

Источник

Возможно, вам также будет интересно:

  • Логические и форматные ошибки сообщений
  • Логические ошибки в программе пример
  • Логические и физические ошибки носителей информации
  • Логические ошибки в обобщении и ограничении понятий
  • Логические и физические ошибки жесткого диска

  • Понравилась статья? Поделить с друзьями:
    0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии