Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Процедуры с параметрами-значениями
Как было сказано ранее, процедуры с параметрами-значениями требуют входных данных. Где они записываются и как задаются? На этот вопрос может ответить общая форма заголовка процедуры этой процедуры: PROCEDURE < Имя процедуры> (< Параметры-аргументы>: тип); Здесь под параметром понимают имя переменной, которая является «входной» для процедуры (формальный параметр-аргумент). Этот параметр с синтаксической точки зрения является параметром-значением, при его описании в заголовке процедуры не требуется писать слово VAR. Параметры-значения при вызове процедуры принимают из основной программы свои конкретные значения. Заметим также, что в самой процедуре значения параметров-значений не меняются в ходе работы процедуры. При обращении к процедуре с параметрами-значениями в основной программе фактическими параметрами могут служить как имена переменных (которые описаны и определены выше), так и конкретные значения (константы) и выражения. При обращении необходимо следить за соответствием списка параметров при обращении и описании. Кроме того, следует строго соблюдать соответствие типов параметров. Рассмотрим работу процедур такого типа на примерах. П р и м е р 1. Нарисовать квадрат с произвольной длиной стороны в левом верхнем углу (длина стороны задается с клавиатуры). В этой программе также надо оформить рисование квадрата в виде процедуры, но уже с входным параметром-значением – длиной стороны квадрата. program RISUNOK_2; var I: integer; procedure KVADRAT (N: integer); var J, K: integer; begin for J: = 1 to N do write ('*'); writeln; for J: = 1 to N - 2 do begin write ('*'); for K: = 1 to N - 2 do write (' '); writeln ('*'); end; for J: = 1 to N do write ('*'); end; begin { Основная программа } write ('Введите длину стороны – '); readln (I); clrscr; KVADRAT (I); end. П р и м е р 2. Вычислить площадь четырехугольника с применением процедуры с параметрами-значениями. program PLOCHAD_2; var AB, BC, CD, AD, AC, S1, S: real; procedure GERON_2 (a, b, c: real); var P: real; begin P: = (a + b + c)/2; S: = sqrt (P*(P - a)*(P - b)*(P - c)); end; begin {*ОСНОВНАЯ ПРОГРАММА*} read (AB, BC, CD, AD, AC); GERON_2(AB, BC, AC); S1: = S; GERON_2 (AD, AC, CD); write ('S = ', S1 + S) end. В данной программе определена процедура GERON_2 с тремя параметрами-значениями и локальной переменной P. Значение же площади треугольника помещается в глобальную переменную S. При вызове этой процедуры формальные параметры a, b, c замещаются на фактические параметры AB, BC, AC при первом обращении и на AD, AC, CD – при втором. Заметим также, что здесь фактические параметры представлены переменными, которые получают свое значение с помощью процедуры READ. Однако если известны длины сторон треугольника, например, 6, 7, 4, то можно вычислить площадь этого треугольника, вызвав процедуру GERON_2(6, 7, 4), и получить ответ в переменной S. Процедуры с параметрами-переменными В отличие от процедур с параметрами-значениями, процедуры с параметрами-переменными не имеют входных параметров, т. е. из основной программы не передаются значения переменных в процедуру, за исключением глобальных переменных. Отличие в описании и обращении к процедурам с параметрами-переменными заключается в специфическом написании заголовка процедуры. В остальном все процедуры схожи. Общий вид заголовка процедуры с параметрами-переменными выглядит так: PROCEDURE < Имя процедуры> ( VAR< Параметры-переменные>: тип); При детальном ознакомлении с синтаксической диаграммой видно, что параметрам-переменным должно предшествовать служебное слово VAR, причем оно пишется столько раз, сколько различных типов представлено в выходных данных, например: PROCEDURE PRIMER (VAR a, b, c: INTEGER; VAR m: CHAR; VAR i, j: REAL). При обращении к процедурам с параметрами-переменными фактическими параметрами должны являться имена переменных, которые описаны в основной программе. П р и м е р. Вычисление площади четырехугольника. program PLOCHAD_3; var AB, BC, CD, AD, AC, S1, S2, a, b, c: real; procedure GERON_3 (var S: real); var P: real; begin P: = (a + b + c)/2; S: = sqrt (P*(P - a)*(P - b)*(P - c)); end; begin { Основная программа } read (AB, BC, CD, AD, AC); a: = AB; b: = BC; c: = AC; GERON_3 (S1); a: = AD; b: = AC; c: = CD; GERON_3 (S2); write ('S = ', S1 + S2) end. 4.1.6. Комбинированные процедуры Комбинированные процедуры включают в себя входные и выходные данные. В заголовке этой процедуры, как и ранее, выходные параметры предваряются словом VAR, входные параметры – без него. Порядок следования параметров может быть произвольным, например: PROCEDURE PRIMER (VAR a, b, c: INTEGER; m: CHAR; VAR i, j: REAL); Здесь a, b, c, i, j – параметры-результаты (переменные); m – параметр-аргумент (значение). В качестве иллюстрации комбинированных процедур рассмотрим последний вариант вычисления площади четырехугольника: program PLOCHAD_4; var AB, BC, CD, AD, AC, S1, S2: real; procedure GERON_4 (a, b, c: eal; var S: real); var P: real; begin P: = (a + b + c)/2; S: = sqrt (P*(P - a)*(P - b)*(P - c)); end; begin {*ОСНОВНАЯ ПРОГРАММА*} read (AB, BC, CD, AD, AC); GERON_4 (AB, BC, AC, S1); GERON_4 (AD, AC, CD, S2); write ('S = ', S1 + S2) end. Примечание. Для более полного усвоения введенных ранее терминов перечислим на базе последнего примера все виды параметров и переменных: 1) глобальные переменные AB, BC, CD, AD, AC, S1, S2; 2) локальные переменные a, b, c, S, P; 3) формальные параметры a, b, c, S: параметры-значения (аргументы) a, b, c; параметр-переменная (результат) S; 4) фактические параметры AB, BC, CD, AD, AC, S1, S2: параметры-значения (аргументы) AB, BC, CD, AD, AC; параметры-переменные (результаты) S1, S2. Заметим также, что термины «параметр-значение» и «аргумент», как и «параметр-переменная» и «результат», не всегда идентичны. Дело в том, что характеристика «значение (переменная)» отражает синтаксическую сущность параметра, а «аргумент (результат)» – его семантику (функциональную роль в процедуре). Иногда один и тот же параметр может быть аргументом и результатом одновременно, но описан в процедуре в виде параметра-переменной. Попытка же описать выходной параметр в виде параметра-значения (без слова VAR в заголовке процедуры) приведет к тому, что результат работы процедуры не будет возвращен в основную программу. Это происходит потому, что характер «поведения» параметров-значений и параметров-переменных в процессе работы процедуры различен. Разница эта состоит в том, что преобразования, которые претерпевают формальные параметры-значения в процедуре, не вызывают изменения соответствующих им фактических параметров, в то время как изменения параметров-переменных могут изменять значения соответствующих фактических параметров. Причиной этого феномена является неодинаковое распределение памяти под хранение параметров процедуры. Формальному параметру-значению отводится некоторая область (ячейка) памяти, куда заносится значение соответствующего фактического параметра, вычисленного на момент обращения к процедуре. На этом связь между ними обрывается. Действительно, если фактическим параметром является константа или выражение, то как изменения в формальном параметре-значении (а это есть всегда переменная) могут повлиять, например, на выражение? Фактическим же параметром, соответствующим формальному параметру-переменной, является всегда переменная. На время выполнения процедуры эти параметры отождествляются, им соответствует одна и та же область памяти. Вполне понятно, что в этой ситуации изменения формального параметра влекут адекватные изменения фактического параметра, и после завершения процедуры его значение может отличаться от его первоначального значения. Именно поэтому, объявив в процедуре параметр-результат как параметр-значение, этот результат так и останется в формальном параметре-переменной без его передачи в соответствующий фактический параметр (т. е нет возврата полученного процедурой значения) в основную программу. Функции пользователя. Рекурсивные функции Функция как объект языка Паскаль является другой версией реализации технологии построения программ с использованием структуры группирования. Можно также сказать, что функция есть частный вид определенного типа процедур, а именно процедур с одним параметром-переменной. Определение функции Функция отличается от процедуры только тем, что всегда возвращает в точку вызова одно скалярное значение. При этом функция, как и процедура, может содержать параметры-значения или быть без них. Общая форма записи заголовка функции FUNCTION имя (список параметров: тип): тип; или FUNCTION имя: тип; Тип результата есть тип значения функции. Список параметров такой же, что и для процедуры, только здесь все параметры являются аргументами. Имя переменной, которая хранит значение функции, совпадает с именем функции. Итак, заголовок функции отличается от заголовка процедуры не только сменой слова PROCEDURE на FUNCTION, но и удалением из списка параметров параметра-результата с присвоением его типа имени функции: PROCEDURE < имя процедуры> (аргументы; FUNCTION < имя функции> (аргументы): тип; Другой особенностью описания функции является наличие в нем хотя бы одного оператора присваивания, в левой части которого стоит имя определяемой функции, а в правой – выражение для вычисления результата функции. Очевидно, что тип этого выражения должен совпадать с указанным в заголовке типом функции. Вызов функции также отличается от вызова процедуры. Если вызов процедуры осуществляется с помощью специального оператора вызова (оператора процедуры), то функция вызывается только внутри некоторого выражения. Для того, чтобы осуществить обращение к функции, необходимо использовать ее имя со списком фактических параметров в каком-либо выражении, тип которого совпадает с типом значения функции. Само же выражение, внутри которого вызывается функция, может быть правой частью оператора присваивания, частью логического выражения и пр. Функции пользователя Известно, что Паскаль имеет набор стандартных функций. Однако этот набор ограничен. Пользователь может по желанию расширить список функций, создав свои функции – функции пользователя. Так, например, в Паскале есть SQR (X) = X2, а вот функции F (X) = Xn, где n принадлежит множеству целых чисел Z, нет. Используя определенное ранее понятие функции, можно создать для этого универсальную функцию, которая давала бы степени произвольного вещественного числа с любым целым показателем. Определим вещественную функцию POWER, которая должна иметь два параметра-аргумента – для показателя и для основания степени: function POWER (FACTOR: real; EXP: integer): real; var COUNT: integer; TFACTOR: real; begin if EXP = 0 then POWER: = 1 else begin TFACTOR: = FACTOR; for COUNT: = 2 to ABS (EXP) do TFACTOR: = TFACTOR*FACTOR; if EXP < 0 then POWER: = 1/TFACTOR else POWER: = TFACTOR end end; Теперь можно эту функцию вызывать следующим образом: а) F: = POWER(5.25, 3); б) WRITELN (" D = ", POWER (5.25, -2): 5: 2); в) IF X > 2*POWER (6.2, 3) THEN WRITE ('ДА'); г) A: = POWER (X, 2) + POWER (X, 3) + POWER (X, 4). Рекурсивные функции К функциям можно обращаться тремя способами: из тела основной программы, из тела другой функции, из тела самой функции, т. е. функция может вызывать саму себя. Функции называются рекурсивными, если в описании функции происходит вызов самой себя, а процесс обращения – рекурсией. Продемонстрируем использование рекурсии на примере вычисления значения факториала произвольного натурального числа N. В математике известно рекурсивное определение факториала: n! = 1 при n = 0; n! = (n - 1)! × n при n > 0. Это рекурсивное определение можно реализовать с помощью соответствующей рекурсивной функции: function FACTORIAL (VALUE: integer): integer; begin iF VALUE = 0 then FACTORIAL: = 1 else FACTORIAL: = VALUE*FACTORIAL (VALUE - 1) end; Теперь можно обращаться к этой функции в теле основной программы, как показано в следующем примере: program FINDFACTORIAL; var N: integer; begin writeln ('Введите число'); readln (N); if N < 0 then writeln ('Нет факториала') else writeln ('Факториал ', N, ' равен ', FACTORIAL (N)) end. Мы видим, что характерной особенностью построенной функции является наличие в ее теле оператора присваивания: FACTORIAL: = VALUE*FACTORIAL (VALUE - 1), где происходит вызов определяемой функции. Здесь идентификатор FACTORIAL в левой части оператора обозначает имя переменной для хранения значения функции, а в правой – имя вызываемой функции. Важным моментом при составлении любой рекурсивной функции является организация выхода из рекурсии. В некоторых простых случаях должно существовать не рекурсивное решение. Рекурсивный процесс должен шаг за шагом так упрощать задачу, чтобы, в конце концов, для нее появилось не рекурсивное решение. В этих функциях должны проверяться значения аргумента для принятия решения о завершении. В нашем случае условием завершения рекурсии является VALUE = 0. При описании рекурсивных функций необходимо хорошо представлять процесс вычислений. Всякая рекурсия состоит из двух этапов: углубления (погружения) внутрь рекурсии и выхода из нее. На первом этапе никаких вычислений не производится, а идет только настройка рабочей формулы на конкретные операнды. На втором этапе происходит процесс вычислений по настроенным формулам. В заключение покажем, что часто рекурсивные функции строятся гораздо проще, чем «обычные», хотя вполне понятно, что не всякая функция может быть переделана на рекурсивную. Сделаем это на примере уже построенной ранее функции POWER. Данная функция явно носит рекурсивный характер, исходя из ее определения: Xn = 1, если n = 0; Xn = Xn-1 * X, если n > 1. Ниже следует рекурсивная функция вычисления значения степени: function POWER (FACTOR: real; EXPONENT: integer): REAL; begin if EXPONENT < 0 then POWER: = 1/POWER (FACTOR, abs (EXPONENT)) else if EXPONENT > 0 then POWER: = FACTOR*POWER (FACTOR, EXPONENT - 1) else POWER: = 1 end; Замечание. Помимо рекурсивных функций, в языке Паскаль по тому же принципу можно определять и рекурсивные процедуры. Подробно о них будет сказано в следующих разделах, а пока покажем, как рекурсивная функция может быть переделана в рекурсивную процедуру на примере вычисления факториала: procedure FACTORIAL (VALUE: integer; var F: integer); begin iF VALUE = 0 then F: = 1 else begin FACTORIAL (VALUE - 1, F); F: = F*VALUE end; end; Здесь уже, в отличие от функции FACTORIAL, для вычисления N! необходимо вызвать эту процедуру с помощью оператора процедуры FACTORIAL (N, FN), где FN – переменная для возвращения из процедуры значения N!. Лабораторная работа №4 Цель работы: научиться создавать и вызывать в Паскаль-программах процедуры и функции, уметь использовать рекурсивные функции. Общие сведения Процедуры и функции являются «строительными блоками» для программ и обеспечивают их модульность, а потому представляют собой важнейшее средство увеличения эффективности программирования. Перед выполнением работы необходимо ознакомиться с правилами оформления и вызова процедур и функций в языке программирования Паскаль. Пример 1. Вычислить значения функции f(x)=2 cos x+3, при x={1; 4; 7, 5; 20}. Вывести результаты в два столбца: в первом - значения x, во втором - значения f(x). Вычисления провести двумя способами: с помощью функции и процедуры. Решение. Аргумент и результат функции – действительные числа, поэтому используем тип Real. В теле функции будет только оператор присваивания – для вычисления значения выражения. Процедура отличается строкой заголовка, - для передачи в основную программу результатов вычислений добавим параметр-переменную fx. Чтобы вывести результаты в виде таблицы, используем форматный вывод. program proc_1; function f (x: Real): Real; begin f: =2*cos(x)+3 end; procedure proc_f (x: Real; var fx: real); begin fx: =2*cos(x)+3 end; var x, fx: real; begin Writeln('с использованием процедуры: '); Writeln(' x f(x)'); x: =1; proc_f (x, fx); Writeln (x: 6: 2, fx: 6: 2); x: =4; proc_f (x, fx); Writeln (x: 6: 2, fx: 6: 2); x: =7.5; proc_f (x, fx); Writeln (x: 6: 2, fx: 6: 2); x: =20; proc_f (x, fx); Writeln (x: 6: 2, fx: 6: 2); Readln; Writeln('с использованием функции: '); Writeln(' x f(x)'); Writeln(1: 6, f (1): 6: 2); Writeln(4: 6, f (4): 6: 2); Writeln(7.5: 6: 2, f (7.5): 6: 2); Writeln(20: 6, f (20): 6: 2); Readln; end. Пример 2. Создать рекурсивную функцию поиска i-го члена последовательности, заданной рекуррентной формулой A1=const1, A2=const2, Ai=3Ai-2-Ai-1. Вывести через пробел значения рекурсивной функции при значениях аргумента от 1 до 10 включительно. Решение. По условию задачи аргумент может принимать только целые значения, поэтому функция имеет параметр-значение типа Integer. Выход из рекурсии в данном случае осуществляется при двух значениях аргумента (при i=1, i=2), поэтому в рекурсивной функции необходимы два вложенных условных оператора или же оператор выбора case. В приведенном примере использованы операторы if, но попробуйте самостоятельно записать решение с помощью оператора выбора. В основной программе значения аргумента - целые последовательные числа, поэтому следует воспользоваться оператором цикла с параметром for. program proc_2; function A (i: Integer): Integer; begin if i=1 then A: =1 else if i=2 then A: =3 else А: =3*A(i-2)-A(i-1) end; var i: Integer; begin for i: =1 to 10 do Write (A(i), ' '); Readln end. Варианты заданий Задание 1. Составить программу для решения задачи с применением функции и процедуры пользователя. a) В правильном треугольнике проведена средняя линия. Найти площадь образовавшейся трапеции, дважды используя функцию вычисления площади правильного треугольника по формуле: b) Для правильного треугольника со стороной а построены вписанная и описанная окружности. Найти площадь образовавшегося кольца, используя функцию вычисления площади круга S=π R2. Для нахождения радиусов окружностей воспользуйтесь формулами: , c) Тариф предусматривает оплату телефонных разговоров следующим образом: при продолжительности разговора меньше P минут стоимость одной минуты составляет S1копеек, в противном случае – S2 коп/мин (S1, S2, P - константы). Используя функцию вычисления стоимости одного разговора, найти суммарную стоимость трех звонков известной продолжительности. d) На товар дважды была сделана скидка – на p1, а затем на p2 процентов. Первоначальная стоимость товара составляла S рублей. Используя функцию вычисления стоимости товара с учетом скидки на P процентов, найти стоимость товара после двойной скидки. Задание 2. Вывести значения рекурсивной функции при значениях аргумента от 1 до 10 включительно. a) Найти член последовательности, заданной формулой: Di=7+Di-1 при i> 1, где D1 определяется пользователем. b) Найти член последовательности, заданной формулой: Ai=Ai-1-Ai-2 при i> 2. Значения первого и второго членов последовательности вводятся пользователем. c) Найти член последовательности, заданной следующим образом: d) Найти член последовательности, заданной формулой Bi=4·Bi-1, при i> 1. Значения первого члена последовательности вводится пользователем. Дополнительные задания 1. Для чисел a, b, c найти значение выражения min(a, ab)+min(a, ac)+1 с использованием функции вычисления минимального из двух чисел. 2. Дан квадрат со стороной а, диагональ этого квадрата является стороной второго квадрата, диагональ второго квадрата – стороной третьего. Найти длину стороны третьего квадрата, используя функцию вычисления длины диагонали квадрата по его стороне: Контрольные вопросы 1. В чем состоит принципиальное отличие процедур от функций? 2. Чем отличается вызов функции от вызова процедуры? 3. Какой переменной присваивается значение в процедуре и в функции? 4. Какие переменные в языке Паскаль называются локальными, а какие глобальными? 5. Какие процедуры и функции называют рекурсивными? 6. Как отличить «обычную» функцию от рекурсивной? 7. Если значения процедуры и функции являются операндами некоторого выражения, то которую из них можно вставить «непосредственно» в это выражение? ОБРАБОТКА МАССИВОВ Скалярный тип – простой тип данных. Скалярное данное неделимо. Массив – это структурированный тип данных. Массив состоит из нескольких элементов. Ко всему массиву можно обращаться по его имени. Можно обращаться к его элементу, но для этого надо задать индекс (индексы). Массивы бывают одномерные и многомерные. Для объявления массива необходимо задать типы его индексов и компонент: ARRAY [Тип индексов] OF < Тип копонент>; Тип компонент массива – это просто тип данных, ассоциированный с каждой компонентой массива. Тип компонент может быть любым REAL, INTEGER, CHAR, BOOLEAN, перечислимым, интервальным. В качестве компоненты массива может быть взят и тип массив. Тип индекса должен быть одним из упорядоченных типов, т. е. любым скалярным типом, кроме REAL: INTEGER, CHAR, интервальный, перечислимый. Тип индекса определяет границы изменения индекса. Если сделана попытка использовать несуществующую компоненту, то возникает ошибка (ошибка неверного индекса). Одномерные массивы Одномерный массив можно задать (объявить) двумя способами: 1. C помощью служебного слова TYPE описывается тип массива, а затем с помощью VAR вводится переменная этого типа. Общая форма записи TYPE < тип массива> = ARRAY [тип индекса] OF < тип компонент>; VAR < переменная>: < тип массива>; 2. С помощью слова VAR сразу описывается переменная типа массив. Общая форма записи VAR < переменная>: ARRAY [тип индекса] OF < тип компонент>; Например, объявление массива из 100 элементов типа REAL можно осуществить двумя способами: 1. type R100 = array [1..100] of real; var A: R100; 2. var A: array [1..100] of real. Здесь задан массив с именем А, и его элементы имеют имена: А[1], …, A[100]. Чаще всего для типа индекса используют интервальный тип на основе типов INTEGER и CHAR. Однако можно в качестве индексов брать перечислимый тип. П р и м е р 1. Подсчет числа вхождений букв в текст определенной длины. program COUNTER; var COUNT: array ['a'..'z'] of integer; CH: char; N: integer; begin for CH: = 'a' to 'z' do COUNT [CH]: = 0; N: = 0; repeat read (CH); N: = N + 1; if (CH > = 'a') and (CH < = 'z') then COUNT [CH]: = COUNT [CH] + 1; until CH = '.'; for CH: = 'a' to 'z' do writeln (CH, COUNT [CH]: 5); end. Пояснение. В этом примере тип индекса есть интервальный тип на базе типа CHAR, а тип компонент есть целое число. Таким образом, элементы массива – числа, а их индексы – буквы, т. е. число элементов массива равно 26 (по числу букв латинского алфавита). Рассмотрим теперь случай, когда тип индекса задан перечислимым типом, а компоненты массива представлены компонентами интервального типа на базе типа INTEGER. П р и м е р 2. Присваивание переменной с именем месяца числа дней этого месяца. program NUMBRDAY; type MONAT = (JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OKT, NOV, DEC); var DAY: array [MONAT] of 28..31; T: MONAT; begin for T: = JAN to DEC do case T of JAN, MAR, MAY, JUL, AUG, OKT, DEC: DAY [T]: = 31; APR, JUN, SEP, NOV: DAY [T]: = 30; FEB: DAY [T]: = 28; end; end. Многомерные массивы Для определения позиции элемента в двумерном массиве необходимы два индекса. Любой двумерный массив есть матрица, а матрица есть таблица. Поэтому удобно описывать двумерные массивы путем указания границ изменения индексов (номеров) строк и столбцов. Например, таблица символов M × N, где M – число строк и N – число столбцов, может быть описана: var TAB: array [1..M, 1..N] of char;
Однако двумерный массив можно интерпретировать как вектор-столбец, каждый элемент которого, в свою очередь, является одномерным массивом (вектор-строка). Этот подход к определению двумерного массива влечет его описание с помощью двух строк, где первая содержит описание строки, а вторая – описание столбца: type LINE = array [1..N] of char; STOLB = array [1..M] of LINE; var TAB: STOLB. Здесь TAB [I] – переменная типа LINE, а TAB [I][J] – переменная типа CHAR.
Эти два вида определения массивов задают и два способа обращения к элементам массива: TAB [I, J] – в первом случае и TAB [I][J] – во втором. Вполне очевидно, что сказанное выше для двумерного массива распространяется и на массивы большей размерности. Например, описание VAR CUBE: ARRAY [1..M, 1..N, 1..K] OF INTEGER определяет задание трехмерного массива целых чисел. Примеры работы с массивами Обработка массивов включает в себя, как правило, следующие компоненты: ввод массива (с клавиатуры или с помощью датчика случайных чисел), вывод полученного массива на экран и собственно его обработка. Все эти компоненты рекомендуется оформлять в виде отдельных процедур. При этом надо учитывать следующий фактор: если процедуре (или функции) будет передаваться массив, то надо объявить в ней этот массив как параметр с атрибутом VAR даже в том случае, если значение массива внутри процедуры не изменяется. Это нужно для того, чтобы не тратить времени и памяти на размещение внутри процедуры копии массива. Заметим, что параметр обязательно должен относиться к типу, имеющему имя. П р и м е р. Сумма элементов таблицы над верхней диагональю. program SUMMA; const M = 10; {число строк таблицы} N = 10; {число столбцов таблицы} type LINE = array [1..n] of integer; TAB = array [1..m] of LINE; var s, i, j: integer; MAS: TAB; procedure VVODMASSIV (var MAS: TAB); begin ¦ for i: = 1 to M do ¦ for j: = 1 to N do ¦ readln (MAS [i][j]); end; procedure VIVODMASSIV (var MAS: TAB); begin ¦ for i: = 1 to M do ¦ begin ¦ ¦ for j: = 1 to N do ¦ ¦ write (MAS [i][j]: 4, ' '); writeln; ¦ end; end; procedure OBRABOTKA (MAS: TAB; var SUM: integer); begin ¦ SUM: = 0; ¦ for i: = 1 to M do ¦ for j: = 1 to N do ¦ if j > i then SUM: = SUM + MAS [i][j]; end; begin | VVODMASSIV (MAS); | writeln ('исходный массив'); VIVODMASSIV (MAS); | OBRABOTKA (MAS, s); writeln; | writeln ('сумма элементов = ', s); end. Лабораторная работа №5 Цель работы: овладеть основными приемами работы с одномерными и двумерными массивами, уметь различать в двумерном массиве обработку строк и столбцов, а также отличать нахождение первых и последних элементов последовательности, обладающих некоторым свойством. Общие сведения Табличное представление информации одно из самых распространенных, поэтому массивы широко применяются в прикладных программах. Перед выполнением работы необходимо ознакомиться с теоретическим материалом по теме «Обработка массивов». Пример 1. Составить программу, позволяющую в одномерном массиве, состоящем из N вещественных элементов, вычислить сумму положительных элементов. Решение. При написании процедур ввода и вывода следует обратить внимание, что элементы – вещественные числа, поэтому необходимо позаботиться о верной обработке дробной части. Вычисление суммы оформим в виде функции с одним аргументом - массивом. Локальными переменными функции будут индексная переменная i и дополнительная переменная s для хранения текущей суммы элементов. В начале тела функции обязательно обнуление s. Каждый элемент массива сравним с нулем, и, если значение положительно, добавим его к искомой сумме s. В конце функции запишем значение переменной s в результирующую переменную. program massiv_1; const N=10; type mas=array [1..N] of Real; procedure Vvodmas(var A: mas); var i: Integer; begin for i: =1 to N do A[i]: =-50+Random(101)+random; end; procedure Vivodmas(A: mas); var i: Integer; begin for i: =1 to N do Write(A[i]: 8: 2); Writeln end; function Summa(A: mas): real; var i: Integer; s: real; begin s: =0; for i: =1 to N do if A[i]> 0 then s: =s+A[i]; Summa: =s; end; var A: mas; begin Randomize; Vvodmas(A); Writeln('Исходный массив: '); Vivodmas(A); Writeln('Ответ: ', Summa(A): 0: 2); Readln end. Пример 2. В двумерном массиве, состоящем из целочисленных элементов, в каждом столбце поменять местами наибольший по модулю и последний не принадлежащий интервалу (a, b) элементы массива. Решение. Преобразования необходимо провести в каждом столбце массива, поэтому параметр внешнего цикла в процедуре обработки - номер столбца j, а вложенного – номер строки i. Для перестановки двух элементов в столбце массива необходимо найти номера их строк n1 и n2, а затем поменять местами значения элементов с использованием промежуточной переменной p. Чтобы найти наибольший по модулю элемент столбца, введем дополнительную переменную max, которая будет хранить максимальное по модулю значение в текущем столбце массива на данный момент. (Можно решить задачу без использования переменной max. Подумайте, как это сделать.) Программа должна корректно работать с любыми входными данными, а значит и в тех случаях, когда некоторые или даже все столбцы массива содержат только элементы из интервала (a, b), и обмен значений в некоторых столбцах или во всем массиве не нужен. const n=10; m=7; type mas=array [1..n, 1..m] of Integer; procedure Vvodmas(var D: mas); var i, j: Integer; begin for i: =1 to n do for j: =1 to m do D[i, j]: =-50+Random(101); end; procedure Vivodmas(D: mas); var i, j: Integer; begin for i: =1 to n do begin for j: =1 to m do Write(D[i, j]: 4); Writeln; end; end; procedure Obmen(a, b: real; var D: mas); var i, j, p, n1, n2, max: Integer; begin for j: =1 to m do begin n1: =1; max: =abs(D[1, j]); {считаем первый элемент столбца наибольшим по модулю} for i: =2 to n do if abs(D[i, j])> max then {обнаружен больший элемент} begin n1: =i; max: =abs(D[i, j]) end; i: =n; {перебираем элементы столбца, начиная с последнего} while (i> =1)and (D[i, j]> a)and(D[i, j]< b) do i: =i-1; n2: =i; if n2< > 0 then {если элемент, не принадлежащий интервалу (a, b), был найден} begin p: =D[n1, j]; D[n1, j]: =D[n2, j]; D[n2, j]: =p; {обмен значений} end; end; end; var D: mas; a, b: Real; begin Randomize; Vvodmas(D); Writeln('Исходный массив: '); Vivodmas(D); Write('Введите через пробел концы интервала (a, b): '); Readln(a, b); Obmen(a, b, D); Writeln('Ответ: '); Vivodmas(D); Readln end. Варианты заданий Задание 1. Составить программу, позволяющую в одномерном массиве, состоящем из N вещественных элементов, вычислить: a) сумму модулей отрицательных элементов массива; b) количество элементов массива, не принадлежащих интервалу (a, b); c) наименьший из элементов массива, принадлежащих отрезку [a, b]; d) количество элементов массива, равных первому элементу; Задание 2. В двумерном массиве, состоящем из целочисленных элементов, поменять местами: a) в каждом столбце наибольший по модулю и последний положительный элементы; b) в каждом столбце первый и последний отрицательные элементы; c) в каждой строке наибольший и наименьший элементы; d) в каждом столбце первый принадлежащий отрезку [a, b] и первый отрицательный элементы; Дополнительные задания 1. Определить в одномерном массиве число соседств из двух чисел разного знака. 2. Дан двумерный массив целых чисел. Поменять местами строку, содержащую максимум массива, со строкой, содержащей его минимум. Контрольные вопросы 1. Как описываются в языке Паскаль одномерный и двумерные массивы? 2. Может ли массив содержать разнотипные данные? 3. В каком порядке указываются индексы при обращении к элементам двумерного массива? 4. Привести пример массива, описание которого выглядит следующим образом: var A: array [1..3, 20..24] of real. 5. Можно ли при обработке двумерных массивов использовать однократные циклы? Если да, то приведите примеры. 6. Если в одномерном массиве проверяется «похожесть» его первой и второй части, то в каких границах надо писать оператор for для «прохождения» по этому массиву? 7. Каким образом надо находить первый и последний элементы одномерного массива, обладающие некоторым свойством (отрицательный, наибольший, входящий в интервал и пр.)? ОБРАБОТКА СТРОКОВЫХ ВЕЛИЧИН В Паскале, как и в других языках программирования, предусмотрена обработка текстов или строк. Для этой цели в языке существует два типа данных: SHAR и STRING. Тип данных CHAR Типу данных CHAR соответствуют символьные константы и переменные. Символьная константа есть какой-то символ алфавита, взятый в апострофы. Символьные переменные получают значения символьных констант с помощью оператора присваивания: ALPFA: = 'p'; A: = 't'; B: = '3'; C: = ' '; D: = ''. Все символы алфавита образуют множество литер. Каждый символ имеет свой код в ASCII. Это позволяет использовать булевские сравнения: =, < >, <, < =, >, > =. Данные этого типа описываются с помощью служебного слова CHAR. Например, переменную ALPFA можно описать как VAR ALPFA: CHAR.
При работе с данными типа CHAR, если у нас есть последовательность символов, существует два способа ввода этих символов с клавиатуры. При первом способе организуется цикл, внутри которого помещается оператор READLN. При этом способе элементы последовательности вводятся поочередно, и после набора на клавиатуре символа необходимо нажать клавишу ввода ENTER. Таким образом, здесь число нажатий клавиши ENTER совпадает с числом вводимых элементов последовательности. Второй способ характеризуется применением для ввода символов оператора READ. С его помощью можно сразу же ввести всю последовательность символов, которая записывается в буфер клавиатуры. Последующий цикл с оператором READ осуществляет уже выборку элементов из этого буфера в соответствующие переменные, указанные в операторе READ. П р и м е р 1. С клавиатуры последовательно вводятся символы. Признаком конца ввода является точка. Составить программу выбрасывания групп символов, расположенных между скобками ( ). Сами скобки тоже выбрасываются. program SKOBKI; var c: char; i: integer; begin ¦ i: = 0; read (c); ¦ while c < > '.' do ¦ begin ¦ ¦ if c = '(' then i: = 1 ¦ ¦ else if c = ')' then i: = 0 ¦ ¦ else if i = 0 then write (c); ¦ ¦ read (c); ¦ ¦ end; end. Пояснение. I = 1 означает, что ранее была прочитана левая скобка, которой пока еще не нашлось парной правой. В этой ситуации прочитанные символы не выводятся на экран. В результате работы этой программы на экране будет представлена строка символов. Здесь вся последовательность символов вводится сразу по первому оператору READ, а затем в цикле из буфера клавиатуры выбираются, анализируются и выводятся на экран символы вне круглых скобок. Например, если вводится последовательность «asg(zx)ytr.», то экран будет выглядеть так: asg(zx)ytr. – результат работы оператора READ; asgytr – результат работы оператора WRITE. В этой программе можно было бы использовать оператор READLN, но тогда после набора каждого символа необходимо нажимать клавишу ввода. Кроме того, на экран будет выводиться не строка символов, а столбец, состоящий из вводимых и отпечатанных элементов. Упорядоченность символов языка используется при написании циклов с параметром, где параметр цикла может пробегать буквенные значения. П р и м е р 2. Программа вывода последовательности букв a, ab, abc, ..., abc... xyz. program SUITE; var c, d: char; begin for c: = 'a' to 'z' do begin for d: = 'a' to c do write (d); writeln (' '); end; end. Массивы литер В рассмотренных программах все символы вводились последовательно в процессе работы цикла или хранились временно в буфере клавиатуры. Это не всегда удобно, поэтому в языках делают строки как последовательность литер. Строку можно задать как массив литер, при этом в качестве длины строки может выступать верхняя граница массива, например: VAR HAMLET: ARRAY [1..17] OF CHAR. Здесь HAMLET – массив литер, компоненты которого имеют тип CHAR; индекс имеет нижнюю границу, равную 1, верхнюю – 17. Для ввода строки в массив HAMLET необходимо организовать цикл из 17 повторений. При каждом повторе этого цикла с клавиатуры вводится очередной символ строки и нажимается клавиша ввода: for n: = 1 to 17 do readln (HA Популярное:
|
Последнее изменение этой страницы: 2016-04-09; Просмотров: 1321; Нарушение авторского права страницы