adfun.ru
| |
BIGLIB |
| большущая библиотека (9812 книг), можно не только прочитать но и скачать бесплатно |
|
| |
ФАНТАСТИКА |
| фентези,
фантастика, фантастические повести |
|
| |
ФИЛОСОФИЯ |
книги, которые заставляют
задуматься над окружающим тебя миром.
|
|
| |
МЕДИЦИНА |
медицинские книги,
методички,
народные лечебники |
|
| |
КУЛИНАРИЯ |
рецепты
тортов, консервирование,
все о спиртных
напитках. |
|
| |
СТИХИ |
| стихи популярных
и не очень авторов |
|
| |
ТВОРЧЕСТВО |
| народное творчество,
стихи, песни и т.д. |
|
| |
ЮМОР |
| анекдоты, приколы,
смешные истории |
|
| |
ЭРОТИКА |
| эротические рассказы,
книги о технике секса,
кама-сутра и др. |
|
|
| |
 |
if List[I] > Max then
begin
Max := List[I];
FindMax := Max
end
end; { FindMax }
TDeb 3.0 #2-3 = 136 =
Эта функция будет прекрасно работать, если максимальным зна-
чением в List не является List[1]. В этом случае никогда не будет
присвоено значение. Правильный вариант функции должен выглядеть
следующим образом:
begin
Max := List[1];
for I := 2 to Count do
if List[I] > Max then
Max := List[I];
FindMax := Max
end; { FindMax }
Уменьшение значения переменных размером в байт или слово
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
Будьте внимательны и не уменьшайте беззнаковое скалярное
значение (размером в слово или байт) при проверке на >= 0. Следу-
ющий фрагмент программы образует бесконечный цикл:
var
w : word;
begin
w:= 5;
while w >= 0 do
w := w - 1;
end.
После пятой итерации w равно 0. При следующем проходе оно
будет уменьшено до значения 65535 (так как переменная размером в
слово принимает значения в диапазоне от 0 до 65535), что также >=
0. В этих случаях следует использовать переменные не типа word
или byte, а типа integer или longint.
Игнорирование границ и особые случаи
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
Заметим, что в обеих версиях функции FindMax в предыдущем
разделе предполагалось, что Count >= 1. Однако в некоторых случа-
ях значение Count может быть равно 0 (то есть список пуст). Если
вы в такой ситуации вызовите функцию FindMax, она возвратит то,
что оказалось в List[1]. Аналогично, если Count > NLMax, выполне-
ние либо завершиться с ошибкой (если разрешена проверка границ),
либо поиск максимального значения будет выполняться в ячейках па-
мяти, не относящихся к List.
Здесь можно предложить два решения. Одно из них состоит, ко-
нечно, в том, чтобы никогда не вызывать функцию FindMax, если
Count не находится в диапазоне 1..NLMax. Это не пустое замечание.
В серьезном программном обеспечении всегда определяются требова-
ния, которые нужно выполнять при вызове определенной программы, а
затем обеспечивается удовлетворение этих требований при вызове.
TDeb 3.0 #2-3 = 137 =
Другое решение состоит в проверке значения Count и, если оно
не находится в диапазоне 1..NLMax, возврате некоторого предопре-
деленного значения. Например, вы можете переписать тело функции
FindMax следующим образом:
begin
if (Count < 1) or (Count > NLMax) then
Max := -32768
else
begin
Max := List[1];
for I := 2 to Count do
if List[I] > Max then
Max := List[I];
end;
FindMax := Max
end; { FindMax }
Однако это приводит к следующему типу ошибок при работе на
Паскале - ошибкам диапазона.
Ошибки диапазона
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
По умолчанию в Турбо Паскале проверка диапазона выключена.
При этом получается более быстрый и компактный код, но в тоже
время при этом вы можете следует определенного типа ошибки, та-
кие, как присваивание переменным значения, выходящего за их до-
пустимый диапазон, или обращение к несуществующему элементу мас-
сива (как показано в приведенном выше примере).
Первый шаг при обнаружении таких ошибок состоит во включении
в программу директивы компилятора {$R+}, которая задает проверку
диапазона, компиляции программы и повторном ее запуске. Если вы
знаете (или догадываетесь), где содержится ошибка, можно помес-
тить указанную директиву перед данной частью программы, а после
нее указать директиву {$R-}, разрешив, таким образом, проверку
диапазона только в той части программы, где содержится ошибка.
Одна из общих ошибок выхода за границы диапазона возникает
при использовании для индексации массива цикла while или repeat.
Предположим, например, что вы ищете элемент массива, содержащий
определенное значение. Вы хотите остановиться после того, как
найдете его, или при достижении конца массива. При нахождении
элементе вы ходите возвратить его индекс, а в противном случае -
0. Ваш первый вариант может выглядеть так:
function FindVal(List : NumList; Count,Val :
integer) : integer;
var
I : integer;
begin
FindVal := 0;
TDeb 3.0 #2-3 = 138 =
I := 1;
while (I <= Count) and (List[I] <> Val) do
Inc(I);
if I <= Count then
FindVal := I
end; { FindVal }
Это прекрасно, но если Val не содержится в List и вы исполь-
зуете обычное вычисление булевских выражений, здесь может возник-
нуть ошибка этапа выполнения. Почему? Потому что когда последний
раз проверка выполняется в начале цикла while I будет равно Count
+ 1. Если Count = NLMax, вы выйдете за пределы List.
Ошибки, специфические для Ассемблера
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
В каждом языке имеется свое множество ошибок, которые обычно
очень легко сделать, но не всегда просто обнаружить. Не является
исключением и язык Ассемблера. Мы рассмотрим некоторые типичные
ошибки, которые допускаются при программировании на Ассемблере, и
дадим рекомендации, как можно их избежать.
Программист забывает о возврате в DOS
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
В Паскале, Си и других языках программа завершается и возв-
ращается в операционную систему DOS автоматически, когда нет
больше выполняемого кода, даже если в программе отсутствует явная
команда ее завершения. В языке Ассемблера это не так. Ассемблер
выполняет только те действия, которые вы явно указываете. Когда
вы запускаете программу, в которой отсутствует команда возврата в
DOS, она просто продолжает работать до конца выполняемого кода
программы и переходит в код, который находится в примыкающей па-
мяти.
TDeb 3.0 #2-3 = 139 =
Программист забывает об инструкции RET
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
Заметим, что правильный вызов подпрограммы состоит из вызова
подпрограммы из другой части кода, выполнения подпрограммы и
возврата из подпрограммы в вызывающую программу. Не забудьте
включать в каждую подпрограмму инструкцию RET, по которой управ-
ление будет передаваться в вызывающий код. При наборе программы
эту директиву легко пропустить. В этом случае ее выполнение за-
кончится ошибкой.
Генерация неверного типа возврата
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
Директива PROC действует двояко. Во-первых, она определяет
имя, по которому будет вызываться процедура. Во-вторых, она уп-
равляет типом (ближним или дальним) процедуры.
Тип процедуры используется Турбо Ассемблером для определения
того, какой тип вызовов нужно генерировать при вызове процедуры
из того же исходного файла. Тип процедуры также используется для
определения типа инструкции RET, которая выполняется, когда про-
цедура возвращает управление в вызывающий код.
Идея здесь очевидна. Инструкции RET в процедуре должны соот-
ветствовать ее типу, не правда ли?
И да и нет. Проблема состоит в том, что возможно и часто же-
лательно группировать отдельные подпрограммы в единую процедуру;
и поскольку эти подпрограммы не имеют соответствующей директивы
PROC, их команды RET соответствуют типу общей процедуры, который
не обязательно соответствует типу каждой отдельной подпрограммы.
Неправильный порядок операндов
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
Многие программисты ошибаются и изменяют порядок операндов в
инструкциях процессора 8086 на обратный. Это, вероятно, связано с
тем, что строка:
|
adfun.ru
|
|
|
|