Студопедия.Орг Главная | Случайная страница | Контакты | Мы поможем в написании вашей работы!  
 

CASEвыражение OF 2 страница



for i:= 1 to dim do

begin b[i]:= - 30 + Random(71);

write(b[i]:3,' ');

end;

for i:= 1 to dim do

begin for j:=dim+1 downto M+1 do

A[i,j]:=A[i,j-1];

A[i,M]:=B[i]

end;

writeln('Массив А');

for i:=1 to dim do

begin for j:=1 to dim+1 do

write(a[i,j]:3,' ');

writeln;

end;

writeln('Создание массива C из четных столбцов массива A');

for j:= 1 to dim do

if (j Mod 2) = 0

then for i:= 1 to dim do

C[i,j Div 2]:= A[i,j];

writeln('Массив C'));

l:=dim div 2;

for i:=1 to dim do

begin for j:=1 to l do

write(c[i,j]:3,' ');

writeln;

end;

readln;

end.

Каким именно образом сгруппировать значения элементов, легко понять, вспомнив, что массив ARRAY[1..3,1..2] OF Single есть на самом деле компактная запись описания ARRAY[1..3] OF ARRAY[1..2] OF Single.

14. Защита от ошибок и отладка программ. Стандартная техника отладки

В программах принято выделять три вида ошибок. Ошибки времени выполнения (Run­time errors), как следует из названия, происходят во время выполнения программы. Во время разработки программы могут возникать синтаксические ошибки и логические ошибки. Под синтаксисом подразумевается структура кода - написание имен и ключевых слов, правила грамматики, пунктуация и т.д. Приведенные ниже фрагменты кода содержат синтаксические ошибки. Сможете ли вы обнаружить их?

if x>y then m:=x; else m:=y; var perem_x,perem_y,rez:integer; begin perem_x:=1; perm_y:=2; rez:= perem_x+ perem_y;

Обнаружение таких ошибок не всегда очевидно, особенно для начинающих программистов. В первом примере перед else стоит “;” и Delphi автоматически обнаружит ошибку. Появится сообщение: ';' not allowed before 'ELSE'. Во втором примере в операторе присваивания неправильно введено имя perm_y (вместо perem_y) и сообщение об ошибке будет следующим: Undeclared identifier: 'perm_y'.

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

var x:single;

begin

x:=10.0;

repeat

writeln(x);

x:=x-3.0/4.0;

until x=0.0;

Дело в том, что переменная х никогда не будет равна 0, и поэтому цикл будет бесконечным. Чтобы прекратить выполнение зациклившейся программы, выберите в главном меню Delphi команду Run Program Reset или воспользуйтесь комбинацией клавиш <Ctrl+F2> при активном окне выполнения программы. А для исправления ошибки нужно заменить предложение until следующим: until x <= 0;

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

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

Как же должен поступать программист, когда при выполнении его программы возникают ошибки? Прежде всего, нужно локализовать ошибку, то есть найти оператор, в котором она произошла. В этом вам может помочь среда Delphi, если в ней правильно установлены опции компилятора. Опции компилятора позволяют изменять режим компиляции (выберите в главном меню Delphi команду Project Options Compiler). Пока нас будут интересовать лишь следующие опции: Range checking, I/O checking, Overflow checking, Debug information. Если они включены, то настройка среды благоприятна для отладки вашей программы. Если они выключены, то их следует включить, а также можно вставить в любом месте исходного кода, где допустима вставка комментариев. Опции записываются в программе в виде: {$ буква + / - }. Каждой опции соответствует своя буква (это заглавные буквы в названии каждой опции), символ "+" означает включить, а символ "-" - выключить. В программе можно задать одну опцию, например, {$O+} или несколько опций - {$R+,I-}. Некоторые опции можно записывать только в самом начале кода программы, другие могут размещаться в любом ее месте.

Опция Range checking (R) отвечает за контроль ошибок Range check error ( ошибка проверки диапазона). Они возникают, например, при попытке присвоить целочисленной переменной недопустимое значение, или при использовании недопустимого индексного выражения для элемента любого массива.

Опция Overflow checking (C) отвечает за контроль ошибок Ariphmetic overflow ( целочисленное переполнение), возникающих при выполнении арифметической операции над целыми числами, когда результат операции выходит за границы соответствующего типа.

Опция I/O cheking (I) отвечает за контроль ошибок ввода-вывода.

Опция Debug information (D) включает в код программы отладочную информацию, что позволяет среде при аварийном завершении программы показать курсором оператор, в котором произошла ошибка.

Стандартными приемами отладки являются дамп данных (выгрузка, вывод дан­ных на экран), ручное выполнение кода и использование встроенного отладчика Delphi.

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

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

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

var x:single;

begin

x:=5;

repeat

x:=x-2;

writeln(x:5:2);

until x=0;

Номер итерации х Выводимое значение
    пусто
     
     
  -1 -1

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

Среда разработки Delphi содержит встроенный отладчик, значительно облегчающий программисту отслеживание кода и обнаружение ошибок. Чтобы отладчик Delphi можно было использовать, нужно убедиться, что режим интегрированной отладки включен. Для этого в главном меню выберите команду Tools Debugger Options (Инструменты Режимы от­ладчика) и на закладке General (Общие) убедитесь, что установлен флажок Integrating debugging (Интегрированная отладка) в левой нижней части диалогового окна.

Команды отладчика доступны из меню Run

Рис. 4

и на панели инструментов отладки Debug (рис. 5).

Рис. 5

Для активизации панели Debug щелкните правой кнопкой мыши на главном меню или на любой видимой панели инструментов (при этом всплывает контек­стное меню Toolbar) и выберите Debug. На рис. 4 показаны пиктограммы, которые на­ходятся на панели инструментов отладки по умолчанию. Кроме того, быстро получить доступ к командам отладчика можно из окна редактора кода. Щелкните правой кнопкой мыши в любом месте окна редактора кода, при этом всплывет контекстное меню, в пунк­те Debug которого перечислены все доступные команды отладчика.

Отладчик Delphi предоставляет полуавтоматические способы обнаружения ошибок. С его помощью программист может наблюдать (Watch) значения определенных переменных или выражений в процессе выполнения программы, причем для этого не нужно встав­лять в код операторы дампа данных. Кроме того, с помощью отладчика можно остано­вить выполнение программы в указанной программистом точке прерывания (breakpoint) или задать пошаговое выполнение программы. Обратите внимание: отладчик - это специальная программа (утилита) времени разработки, команды отладчика нельзя использовать в программе, вы­полняющейся за пределами среды разработки Delphi.

Приведем короткое описание точек прерывания (breakpoint), пошагового выполнения (step) и окон наблюдения (watch). Точки прерывания выполнения исходного кода устанавливаются программистом слева от строки кода, перед которой нужно остановить выполнение. Их можно устанавливать только на выполнимых строках кода (нельзя на пустых строках, операторах объявления и комментариях). Когда при выполнении исходного кода встречается точка прерывания, программа временно останавливается, пока программист не выберет команду Run меню Run или не щелкнет на кнопке Run панели отладки.

Когда программа остановлена, программист может просмотреть и/или изменить значения выражений в окне Evaluate/Modify (Оценить/ Изменить).

В процессе интерактивной отладки значения переменных и выражений можно просматривать также с помощью всплывающего окна указателя (tooltip). Для этого нужно всего лишь поместить указатель мыши на переменную или выражение в ре­дакторе кода и через одну секунду (по умолчанию) Delphi выведет во всплывшем окне значение этой переменной или выражения.

Для включения режима вывода всплывающего окна указателя выберите в главном меню команду Tools Editor Options... (Инструменты Параметры редактора...), от­кроется окно Editor Options. Затем во вкладке Code Insight (Подсказка кода) устано­вите флажок Tooltip expression evaluation (Оценивание и вывод выражений во всплы­вающее окно). Обратите внимание: при этом должен быть установлен режим Inte­grated Debugging (Интегрированная отладка).

В отладчике Delphi есть две операции пошагового выполнения. Операция Trace Into (Отследить в) выполняет за один шаг один оператор исходного кода. Например, если оператором является вызов подпрограммы, то следующим будет выполнен первый опе­ратор вызванной подпрограммы, после чего программа опять остановится. В то же время операция Step Over (Перешагнуть через) выполняет всю подпрограмму как одно целое - выполнение программы остановится на следующем операторе текущей подпрограммы независимо от того, является ли он вызовом подпрограммы.

Наблюдаемое выражение (watch expression) — это определенное программистом выра­жение (оно может не входить в исходный код), значение которого программист может наблюдать во время выполнения программы. Значения наблюдаемых выражений видны в окне наблюдения (Watch window), в режиме прерываний они автоматически обновляют­ся. Кроме того, в окне локальных переменных (Local variable window) автоматически выво­дятся значения всех объявленных локальных переменных текущей подпрограммы.

Чтобы практически освоить приемы работы с отладчиком Delphi, рассмотрим следующий пример. При этом настоятельно рекомендуем проделать все действия за компьютером.

1. Числа Фибоначчи определяются как последовательность значений , где , . Приведенная ниже подпрограмма выводит числа Фибонач­чи, значение которых меньше или равно 30 000, и квадраты каждого из этих чисел:

{Это функция, вычисляющая квадрат целого числа}

function Square(value: Integer): Integer;

begin

Square:= value * value;

end;{ Square }

{Вывод чисел Фибоначчи, значения которых меньше, или равны 30000}

var num1,num2,sum: Integer;

begin

num1:= 1;

num2:= 1;

writeln(Rus('Число Фибоначчи Квадрат числа'));

writeln(num1:10, Square(num1):15);

repeat

writeln(num2:10, Square(num2):15);

sum:= num1 + num2;

num1:= num2;

num2:= sum;

until (num2 > 30000);

readln

end.

2. Поставьте точку прерывания на первую строку тела цикла repeat. Для этого по­местите на этой строке курсор мыши, щелкните правой кнопкой и во всплывшем меню выберите команду Debug Toggle Breakpoint (Отладка Переключение точки прерывания). Другой способ сделать это — установить на строку указатель мыши и нажать клавишу <F5>, которая переключает точку прерывания (чтобы увидеть, как она переключается, нажмите <F5> несколько раз). Обратите внимание: редак­тор кода выделяет строку и располагает слева от нее красный кружочек, как пока­зано на рис. 6. Еще один способ установки точки прерывания — щелкнуть левой кнопкой мыши на серой полосе слева от строк кода (там, где устанавливается красный кружочек).

Рис.6

3. Выполните программу. Как видите, отладчик Delphi остановил выполнение программы в точке прерывания и вывел окно редак­тора кода (рис. 7). В окне редактора отмечена следующая строка, которая пока не выполнена, при этом на левой серой полосе появилась зеленая стрелка - указатель инструкций (instruction pointer).

Рис.7

4. Выполняйте строки кода путем последовательных щелчков на кнопке Trace Into (Отследить в) или нажатий клавиши <F7>. Обратите внимание: указатель инст­рукции попадает внутрь подпрограммы Square (). Сделав еще два щелчка, верни­тесь в основную программу.

5. Установите наблюдение за переменными numl и value. Для этого выберите ко­манду Run Add Watch... (Выполнить Добавить наблюдение) или нажмите клави­ши <Ctrl+F5>. Появится окно Watch Properties (Свойства наблюдения), показан­ное на рис. 8.

Рис.8

В области Expression (Выражение) введите num2 и нажмите клави­шу <Enter>. Сделайте то же самое для переменной value. Еще один способ быст­рой установки наблюдения за выражением - щелкнуть в редакторе кода правой кнопкой мыши на нужном выражении и во всплывшем меню выбрать команду Debug Add Watch at Cursor (Отладка Установка наблюдения в точке указателя мыши).

6. Чтобы отследить работу программы, несколько раз нажмите клавишу <F7>. Обратите внимание: в процессе пошагового выполнения значения в окне наблюдений изме­няются. Продолжая нажимать клавишу <F7>, дождитесь момента, когда указатель инструкций по­падет в точку прерывания.

7. Чтобы перешагнуть через вызов функции Square (), нажмите клавишу <F8>. Об­ратите внимание: указатель инструкций не вошел в функцию Square (), а пере­местился в следующую строку кода текущей подпрограммы.

8. Удалите все наблюдения за значениями переменных. Для этого щелкните правой кнопкой мыши на окне на­блюдений и во всплывшем меню выберите команду Delete All Watches (Удалить все наблюдения). Закройте окно наблюдений Watch List.

9. В редакторе коде щелкните на строке с точкой прерывания. Нажав клавишу <F5>, отключите точку прерывания.

10. Нажав клавишу <F9>, возобновите выполнение программы. Затем закройте окно с результатами выполнения программы.

15. Процедуры и функции. Сфера действия описаний

В языке Object Pascal (как вы уже поняли из предыдущего материала) существуют понятия процедуры и функции. Процедуры и функции можно определить как замкнутые программные единицы, реализующие некоторый алгоритм. Разработка функций и процедур необходима при многократном использовании в разных местах программы или в нескольких программах блока операторов, выполняющих однотипные действия, например, расчет значений сложной функции при различных значениях аргумента.

Процедуры и функции, определяемые программистом, приводятся в разделе описания основной программы. Процедуры и функции имеют заголовок, раздел описания и раздел операторов. Раздел операторов начинается с BEGIN и заканчивается END; (но не END.). Единственным новым оператором для нас будет оператор заголовка, с которого начинается всякая процедура и функция. Заголовок процедуры состоит из служебного слова Procedure, имени процедуры и списка параметров

PROCEDURE имя ( список параметров );

Здесь имя - имя процедуры (любой идентификатор), список параметров может отсутствовать, но если он есть, записывается в круглых скобках после имени процедуры и имеет вид:

[ VAR ] имя,... имя: тип;...........................; [ VAR ] имя,... имя: тип

Здесь имя - имена параметров, каждый параметр может использоваться внутри процедуры как обычная переменная соответствующего типа. Тип - имя типа, но не описание пользовательского типа; скажем, описание параметра в виде x:1..5 неверно, но, если выше описан соответствующий тип: TYPE MyType=1..5, то параметр можно описать в виде x:MyType. Ключевое слово VAR перед описанием параметров означает в данном случае, что все параметры до "; " или до " ) " - параметры-переменные; если же VAR отсутствует, то параметры являются параметрами-значениями. Смысл этих понятий мы рассмотрим чуть позже.

Процедуры вызываются в других процедурах и функциях с помощью уже известного вам оператора вызова:

имя ( список аргументов );

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

procedure outvar(x:single; name:char);

begin

writeln(Rus('переменная '),name,Rus(' равна '),x:10:4);

end; {outvar}

var a,b,c,d: single;

begin

writeln(Rus('Введите переменные a,b,c,d '));

readln(a,b,c,d);

outvar(a,'a'); outvar(b,'b');

outvar(c,'c'); outvar(d,'d');

readln

end.

Наша процедура OutVar получает из главной процедуры вещественное число х и символ Name, но ничего не передает обратно. Теперь попробуем написать процедуру, которая по заданным значениям x и y вычисляет cos(x)+cos(y) и cos(x)-cos(y):

procedure t(x,y:single; cplus,cminus:single);

begin cplus:=cos(x)+cos(y);

cminus:=cos(x)-cos(y);

end; {t}

var p,m:single;

begin

t(1.235,0.645,p,m);

writeln(p:7:3,m:7:3);

readln

end.

Запустим эту программу и - вместо правильного результата 1.129,-0.470 -получим в лучшем случае нули. Дело в том, что через параметры-значения (а Cplus и Cminus описаны в нашей процедуре как параметры-значения!) невозможно передать информацию из процедуры, но лишь в процедуру. Чтобы правильно решить нашу задачу, следует Cplus и Cminus описать в заголовке как параметры-переменные:

procedure t(x,y:single;var cplus,cminus:single);

begin cplus:=cos(x)+cos(y);

cminus:=cos(x)-cos(y);

end; {t}

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

Функция, в отличие от процедуры, всегда вычисляет некоторое значение скалярного типа, которое внутри функции должно быть присвоено имени функции. Заголовок функции имеет вид:

FUNCTION имя ( список параметров ): тип;

В остальном функции аналогичны процедурам. Обращение к функции осуществляется с помощью указателя функции: имя ( список параметров ) Указатель функции может использоваться как и любое другое выражение того же типа, но это не оператор. Запишем пример функции:

function Na3(x:LongInt):Boolean;

begin

Na3:=x MOD 3=0;

end; {Na3}

var L:LongInt;

begin write(Rus('Введите целое число '));

read(L);

write(Rus('Число '),L);

if not Na3(L)

then write(Rus(' не'));

writeln(Rus(' делится на 3!'));

readln; readln;

end.

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

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

function factorial(n:byte):single;

begin if n<=1 then factorial:=1

else factorial:=n*factorial(n-1);

end;

Теперь запишем этот алгоритм по-другому:

function factorial(n:byte):single;

var i:byte; f:single;

begin f:=1; for i:=2 to n do f:=f*i; factorial:=f;

end;

Но обратите внимание: в этих примерах предполагается, что число, для которого будет найдено значение факториала, не превосходит 255, а результат не будет превышать 3.4Е+38. Если мы попытаемся найти значение факториала для 34, то после выполнения соответствующей программы получим 2.952328Е+0038. Но вот попытка поиска значения факториала для 35 не завершится успехом. А если определить тип результата функции factorial как integer, то значения аргумента, для которых можно получить значение функции, соответствующее действительности, еще меньше. Подумайте, в чем здесь ошибка и как ее можно исправить.

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

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

  Таблица 5
Место объявления идентификатора Область видимости
Объявление в подпрограмме От точки объявления до конца текущей подпрограммы, включая все внутренние подпрограммы
Объявление в программе От точки объявления до конца текущей программы, включая все внутренние подпрограммы

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





Дата публикования: 2014-11-04; Прочитано: 316 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!



studopedia.org - Студопедия.Орг - 2014-2024 год. Студопедия не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования (0.027 с)...