программирование на паскале2. Учебное пособие по курсу Высокоуровневые методы информатики и программирования для студентов Гуманитарноприкладного института
Скачать 0.89 Mb.
|
Динамические массивыДля алгоритмических языков, требующих компиляции, основной трудностью работы со статическими массивами является обязательность указания количества их элементов при объявлении. В частности, в Паскале границами индексов массива в инструкции array могут быть только константы. Единственным способом работы с массивами переменной длины являются динамические переменные. Классический подход к работе с массивами переменной длины, который в настоящее время используется, например, в алгоритмическом языке Си, состоит в следующем. После определения числа n элементов массива (например, посредством ввода) с помощью процедуры, аналогичной GetMem(p,n), выделяется область памяти под массив. Указатель p при этом ссылается на первый элемент массива. Адреса остальных элементов легко вычисляются по их индексам. Например, адрес i-го элемента в одномерном массиве равен p+(i-1)*s, где s – количество байтов, занимаемых одним элементом. В Объектном Паскале такой подход невозможен, так как ограничено использование арифметических операций над указателями. Это ограничение позволяет увеличить надежность программы за счет уменьшения вероятности несанкционированного доступа к памяти из-за неправильного определения адресов. Как альтернатива описанного выше подхода, в Объектном Паскале для работы с массивами переменной длины определен специальный тип – динамические массивы. Описание динамического массива: Var имя_массива: Array of Array of…Array of тип_элемента; Ключевые слова Array of записываются в описании столько раз, сколько индексов у массива. По существу объявленное имя_массива является указателем на массив. Начальное значение индексов динамического массива равно нулю. Выделение памяти под массив осуществляется с помощью процедуры SetLength (см. также §3.1.2). Вызов этой процедуры имеет вид: SetLength(имя_массива, размер1, размер2,…,размерM). В скобках указываются размеры массива по первым M (не обязательно всем) индексам. Пример 1. В приведенном ниже фрагменте программы выделяется память под вещественный одномерный массив a размером n и под целочисленную матрицу b из n строк и m столбцов. Значения n и m предварительно задаются вводом. Var a:Array of Real; b:Array of Array of integer; n,m:integer; Begin Readln(n,m); SetLength(a,n); SetLength(b,n,m);… Для работы с массивами (необязательно динамическими) также используются функции: Length(a) – возвращает размер массива a по первому индексу; Low(a) – возвращает наименьший номер компонента массива a (для динамических массивов ноль); High(a) – возвращает наибольший номер компонента массива a; SizeOf(a) –возвращает число байтов памяти, занимаемых массивом a. Для освобождения памяти, отведенной под динамический массив, достаточно присвоить его имени значение nil. Пример 2. В приведенной ниже программе осуществляется ввод и вывод динамической матрицы, размеры которой задаются вводом. program Primer2; Var a:Array of Array of real; n,m,i,j:integer; {n,m – размеры матрицы} {i,j – счетчики строк и столбцов} Begin writeln(’Input count of rows’); readln(n); writeln(’Input count of columns’); readln(m); SetLength(a,n); {отводится память под указатели на строки} writeln(’Input array ’, n, ’*’,m); for i:=0 to High(a) do {High(a)=n-1)} begin Setlength(a[i],m); { отводится память под элементы строки} for j:=0 to High(a[i]) do {High(a[i]=m-1} read(a[i,j]); end; readln; {закончен ввод динамического массива} // обработка матрицы – заглушка writeln(’ output of dynamic array’); for i:=0 to High(a) do begin for j:=0 to High(a[i]) do write (a[i,j]:7:2); writeln; a[i]:=nil; {освобождение памяти из-под строки} end; a:=nil;{ освобождение памяти из-под указателей на строки } readln End.
В части II приводились примеры подпрограмм с параметрами-массивами. Тип массивов объявлялся до описания подпрограмм в разделе типов, причем размеры выбирались по максимальной длине фактических массивов, используемых в данной задаче. Такой подход, несомненно, имеет два недостатка: во-первых, теряется универсальность подпрограммы, а, во-вторых, память по фактические массивы объявляется с избытком. В рассматриваемых версиях Паскаля допускается в списке формальных параметров использовать конструкцию Array of типбез указания границ массивов. Такие массивы называются открытыми. Соответствующим фактическим параметром может быть как динамический, так и статический массив произвольного размера. Открытые массивы могут быть только одномерными, но их компоненты могут иметь сложный тип. Нумеруются элементы открытых массивов начиная с нуля. При работе с открытыми массивами, наряду с функциями High, Low, Length, может быть полезна функция Slice(массив, количество_элементов), возвращающая начальную часть массива. Пример 1. Приведенная программа вычисляет максимальные значения элементов двух одномерных массивов. Подпрограммы ввода и обработки используют открытые массивы. program Project1; Var A:Array[1..5] of real; B:Array[1..8] of real; Procedure masin( c:char; Var A:array of real); Var i:integer; begin writeln('input vector',c,' size of ',Length(A)); for i:=Low(A) to High(a)do read(A[i]); readln; end{masin}; Function max( Var A:array of real):real; Var i:integer;mx:real; begin mx:=a[Low(A)]; for i:=Low(A)+1 to High(A) do if mx mx:=A[i]; max:=mx end{max}; begin masin('A',A); masin('B',B); writeln('maxa=',max(A),' maxb=',max(b)); readln end. Пример 2. В отличие от примера 1, приведенная программа позволяет обрабатывать не все элементы массивов (в соответствии с описанием), а только совокупность первых элементов массивов, число которых задается вводом. Эта возможность обеспечивается применением функции Slice. program Project2; Var A:Array[1..10] of real; B:Array[1..10] of real; nA,nB:integer; Procedure masin( c:char; Var A:array of real); Var i:integer; begin writeln('input vector',c,' size of ',Length(A)); for i:=Low(A) to High(a)do read(A[i]); readln; end{masin}; Function max( Var A:array of real):real; Var i:integer;mx:real; begin mx:=a[0]; for i:=Low(A)+1 to High(A) do if mx mx:=A[i]; max:=mx end{max}; begin writeln('Input number of components of array A'); readln(nA); masin('A',Slice(A,nA)); writeln('Input number of components of array B'); readln(nB); masin('B',Slice(B,nB)); writeln('maxa=',max(Slice(A,nA)),' maxb=',max(Slice(B,nB))); readln end. Пример 3. Этот пример показывает, как использовать подпрограммы с формальными параметрами, являющимися открытыми массивами, для обработки динамических матриц. Программа вычисляет и выводит сумму элементов каждой из двух матриц. Размеры матриц задаются вводом. На значения размеров не накладывается никаких ограничений. program Project3; Type str=array of real;{тип строки матрицы – динамический массив} Var nA,mA,nB,mb:integer; A,B:array of str; Function Sum(n,m:integer; Var a:array of str):real; Var s:real; i,j:integer; Begin s:=0; for i:=0 to n-1 do for j:=0 to m-1 do s:=s+a[i][j]; sum:=s End {Sum}; Procedure InMatr(n,m:integer; c:char;Var A:array of str); Var i,j:integer; Begin writeln('input matrix ', c, ' size of ', n, '*', m); for i:=0 to n-1 do begin SetLength(a[i],m); for j:=0 to m-1 do read(a[i][j]); end; readln; End; begin writeln ('Input sizes of matrix A'); readln (nA,mA); SetLength(A,nA); InMatr(nA,mA,'A',A); writeln ('Input sizes of matrix B'); readln (nB,mB); SetLength(B,nB); InMatr(nB,mB,'B',B); writeln('sumA=',Sum(nA,mA,A):6:1,' sumB=',Sum(nB,mB,B):6:1); readln; end. |