Функции пользователя. Рекурсивные функции

Функция как объект языка Паскаль является другой версией реализации технологии построения программ с использованием структуры группирования. Можно также сказать, что функция есть частный вид определенного типа процедур, а именно процедур с одним параметром-переменной.

Определение функции

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

Общая форма записи заголовка функции

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

или

FUNCTION имя: тип;

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

Итак, заголовок функции отличается от заголовка процедуры не только сменой слова PROCEDURE на FUNCTION, но и удалением из списка параметров параметра-результата с присвоением его типа имени функции:

PROCEDURE <имя процедуры> (аргументы;
VAR параметр-результат: тип);

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) В правильном треугольнике проведена средняя линия. Найти площадь образовавшейся трапеции, дважды используя функцию вычисления площади правильного треугольника по формуле:

Функции пользователя. Рекурсивные функции - student2.ru

b) Для правильного треугольника со стороной а построены вписанная и описанная окружности. Найти площадь образовавшегося кольца, используя функцию вычисления площади круга S=πR2. Для нахождения радиусов окружностей воспользуйтесь формулами:

Функции пользователя. Рекурсивные функции - student2.ru , Функции пользователя. Рекурсивные функции - student2.ru

c) Тариф предусматривает оплату телефонных разговоров следующим образом: при продолжительности разговора меньше P минут стоимость одной минуты составляет S1копеек, в противном случае – S2 коп/мин (S1, S2, P - константы). Используя функцию вычисления стоимости одного разговора, найти суммарную стоимость трех звонков известной продолжительности.

d) На товар дважды была сделана скидка – на p1, а затем на p2 процентов. Первоначальная стоимость товара составляла S рублей. Используя функцию вычисления стоимости товара с учетом скидки на P процентов, найти стоимость товара после двойной скидки.

Функции пользователя. Рекурсивные функции - student2.ru

Задание 2. Вывести значения рекурсивной функции при значениях аргумента от 1 до 10 включительно.

a) Найти член последовательности, заданной формулой: Di=7+Di-1 при i>1, где D1 определяется пользователем.

b) Найти член последовательности, заданной формулой: Ai=Ai-1-Ai-2 при i>2. Значения первого и второго членов последовательности вводятся пользователем.

c) Найти член последовательности, заданной следующим образом:
y1=0; y2=10; yn=2×yn-1-yn-2, где n>2.

d) Найти член последовательности, заданной формулой Bi=4·Bi-1, при i>1. Значения первого члена последовательности вводится пользователем.

Дополнительные задания

1. Для чисел a, b, c найти значение выражения min(a, ab)+min(a, ac)+1 с использованием функции вычисления минимального из двух чисел.

2. Дан квадрат со стороной а, диагональ этого квадрата является стороной второго квадрата, диагональ второго квадрата – стороной третьего. Найти длину стороны третьего квадрата, используя функцию вычисления длины диагонали квадрата по его стороне:

Функции пользователя. Рекурсивные функции - student2.ru

Содержание отчета

1. Постановка задачи.

2. Описание алгоритма.

3. Тестовые примеры и анализ результатов тестирования.

4. Вывод.

Контрольные вопросы

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;

Общая форма записи VAR <имя> : ARRAY [тип индекса строки, тип индекса столбца] OF <тип компонент>;

Однако двумерный массив можно интерпретировать как вектор-столбец, каждый элемент которого, в свою очередь, является одномерным массивом (вектор-строка). Этот подход к определению двумерного массива влечет его описание с помощью двух строк, где первая содержит описание строки, а вторая – описание столбца:

type LINE = array [1..N] of char;

STOLB = array [1..M] of LINE;

var TAB : STOLB.

Здесь TAB [I] – переменная типа LINE, а TAB [I][J] – переменная типа CHAR.

Общая форма записи TYPE <тип строки> = ARRAY [тип индекса] OF <тип компонент>; <тип столбца> = ARRAY [тип индекса] OF <тип строки>; VAR <переменная массива> : <тип столбца>;

Эти два вида определения массивов задают и два способа обращения к элементам массива: 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. Вывод.

Контрольные вопросы

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.

Общая форма записи VAR <переменная>: 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 (HAMLET [n]).

Этот массив можно образовать и с помощью однократного нажатия клавиши ввода после набора всех элементов строки:

for n := 1 to 17 do read (HAMLET [n]).

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

for n := 17 downto 1 do write (HAMLET [n]).

Тип данных STRING

Наряду с тем положительным, что дают нам массивы литер, они обладают существенным недостатком: их длину нельзя менять во время выполнения программы. Так, описанная переменная HAMLET в п. 7.2 есть массив из 17 элементов, и, следовательно, туда можно поместить только текст, содержащий ровно 17 символов.

Это не всегда удобно. Хотелось бы иметь такую переменную, в которую можно было бы поместить текст произвольной (но ограниченной) длины. Такую возможность предоставляет тип STRING. Так, объявив переменную var HAMLET: string [17], можно путем оператора присваивания (а не через цикл) задать ей значение текста произвольной длины (от 0 до 17), например:

HAMLET := 'Быть или не быть';

HAMLET := 'Бедный Йорик';

HAMLET := ' '; HAMLET:= ''.

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

Общая форма записи TYPE <имя типа> = STRING [N]; VAR <имя переменной>: <имя типа>; или VAR <имя переменной>: STRING [N];

Здесь N – целая константа, задающая максимальную длину текста. Доступ к элементам строки производится с помощью индексов, так как в этом типе также все элементы имеют свой (числовой) индекс от 1 до N. В результате получается величина типа CHAR, например:

HAMLET := 'ПРОГРАММА';

HAMLET [1] = 'П'; HAMLET [9] = 'А'.

Тип STRING и стандартный тип CHAR совместимы. Строки и символы могут употребляться в одних и тех же строковых выражениях.

Строковое выражение состоит из строковых (символьных) констант, переменных, указателей строковых функций и операции конкатенации (склеивания) строк, обозначаемой знаком «+». Строки можно сравнивать. В результате сравнения двух строк истина получается только в том случае, если сравниваемые строки совпадают посимвольно и имеют одинаковую длину (принадлежат одному и тому же типу).

Наши рекомендации