Двумерные массивы называют матрицами. У них первый индекс означает номер строки, второй – номер столбца.
Пример 1. Описания типов двумерных массивов:
type quad_matr = array[1..n,1..n] of real;
mas_2d = array[1..n+m,1..10] of integer;
Пример 2. Непосредственные описания переменных как двумерных массивов:
var A,B,C:array[1..5,1..10] of integer;
matr:array[1..m,1..m] of longint;
Графически матрицы изображают в виде таблиц. Например, на рис.8.1 дана матрица с 4 строками и 4 столбцамикоторую обозначим А. При размещении в памяти и обработке многомерных массивов действует следующее правило адресации элементов в массиве: первым возрастает самый правый индекс, затем второй справа и т.д. Для матриц это означает, что их элементы располагаются по строкам. В математике матрицу А, имеющую n строк и m столбцов обозначают как А(n´m).
-11 | -23 | -11 | -23 | -11 | -23 | ||||||||
-4 | -10 | -68 | -27 | -4 | -10 | ||||||||
-14 | -84 | -14 | -84 | -14 | -84 | ||||||||
-68 | -27 | -4 | -10 | -68 | -27 |
Рис.8.1 Рис. 8.2 Рис. 8.3
Пример 3. Элементы матрицы А[1..4,1..4] (рис.8.1) располагаются в памяти в следующем порядке: А[1,1]; А[1,2]; А[1,3]; А[1,4]; А[2,1]; А[2,2]; А[2,3]; А[2,4]; А[3,1]; А[3,2]; А[3,3]; А[3,4]; А[4,1]; А[4,2]; А[4,3]; А[4,4].
Если рассматривать матрицу А(n´m) в виде линейного массива L длины n × m, то каждой паре индексов [ i,j ] в матрице А взаимно однозначно соответствует индекс, равный ((i-1) × m + j) в линейном массиве L.
Для инициализации двумерных массивов используют обычные приемы. В примере 1 п.8.3 дано обнуление элементов двумерного массива. При инициализации двумерных массивов с использованием типизированных констант значения компонент каждого из входящих в него одномерных массивов записываются в скобках.
Пример 4. Инициализация матрицы M[1..2,1..3] с использованием типизированной константы:
type Matr= Array[1..3,1..2] of Integer;
const M: Matr= ((2, -8)
(-5, 41)
(53, -26));
Для ввода и вывода двумерных массивов применяют методы, аналогичные одномерным с той разницей, что вместо одного арифметического цикла используют два вложенных.
Пример 5. Ввод в матрицу a размерами 5´4 случайных чисел, лежащих на отрезке [0;1]:
var a:array[1..5,1..4] of real;
i,j:integer;
Begin
for i:=1 to 5 do
for j:=1 to 4 do a[i,j]:=random;
End.
Пример 6. Построчный вывод элементов матрицы a из примера 5 размерами 5´4: случайных чисел, лежащих на отрезке [0;1]
for i:=1 to 5 do begin
for j:=1 to 4 do write(' a[',i,',',j,']=',a[i,j]:8:6); {вывод строки элементов}
writeln; {переход на очередную строку}
End;
Простейшим видом задач является поиск положения и значения элемента матрицы, обладающего каким-либо свойством.
Пример 7. Ввести с клавиатуры элементы матрицы M[1..2,1..3] с элементами типа integer и вывести матрицу на экран. Определить в ней максимальный отрицательный элемент. Найденный элемент и его номер выдать на экран. Если в матрице нет отрицательных элементов, вывести сообщение “No”.
Решение. Обозначим искомый номер строки элемента через M_str, столбца - через M_stl его значение – через Max. Начальное значение Max примем равным (-32768) – минимально возможному значению типа integer. В качестве начального значения номера M_str примем 0 - номер не существующей строки: M_str=0. Если значение M_str=0 не изменилось до конца расчета, то это означает, что ни одного отрицательного элемента в матрице нет.
var a:array[1..2,1..3] of integer;
i,j,M_str, M_stl,Max:integer;
Begin
for i:=1 to 2 do {ввод элементов матрицы с клавиатуры}
for j:=1 to 3 do begin
writeln('vvedite element a[',i,',',j,']='); {запрос на ввод элемента a[i,j] }
read(a[i,j]); {ввод элемента a[i,j] }
End;
for i:=1 to 2 do begin {вывод матрицы на экран}
for j:=1 to 3 do write(' a[',i,',',j,']=',a[i,j]:6); {вывод строки элементов}
writeln; {переход на очередную строку}
End;
Max:=-32768; M_str:=0; {начальные присвоение значения Max и M_str }
for i:=1 to 2 do
for j:=1 to 3 do
if(a[i,j]<0)and(a[i,j]> Max)then {сравнение отрицательных элементов матрицы с Max }
begin Max:=a[i,j]; M_str:=i; M_stl:=j end; {коррекция Max, M_str и M_stl }
if M_str=0 then writeln(' NO!') else {проверка, была ли хоть одна коррекция Max }
writeln(' Max:=',Max,' M_str=',M_str,' M_stl=', M_stl); {вывод результатов}
End.
Для определенности будем рассматривать целочисленную матрицу с названием a, число строк которой обозначено как n, число столбцов – как m. Целочисленные индексы, пробегающие по строкам и столбцам, обозначим i и j. Матрицы, у которых числа строк и столбцов равны (n=m), называют квадратными. Пример квадратной матрицы а(4´4) дан на рис.8.1. Для квадратных матриц вводят понятия главной диагонали – упорядоченный набор элементов вида {m[1,1], m[2,2],..., m[n,n]}, у которых совпадают номера строки и столбца. У матрицы на рис.8.1. на главной диагонали стоят элементы: а[1,1]=5, а[2,2]=6, а[3,3]=72, а[4,4]=-27.
Рассмотрим типовые операции, предусматривающие изменение значений элементов матрицы. Для круговой пересылки целых величин используем вспомогательную целую величину t. Фрагменты кода, выполняющие операции, даны для матрицы а(n´m) (a[1..n,1..m]).
1. Перестановка строк и столбцов:
а) перестановку строк с номерами r и s:
for j:=1 to m do {перебор всех столбцов матрицы от 1 до m }
begin t:=a[r,j];a[r,j]:=a[s,j];a[s,j]:=t end; {круговая пересылка элементов строк r,s }
б) перестановку столбцов с номерами p и q:
for i:=1 to n do {перебор всех строк матрицы от 1 до n }
begin t:=a[i,p];a[i,p]:=a[i,q];a[i,q]:=t end; {круг. пересылка элементов столбцов p,q }
Для матрицы с рис.8.1 результаты перестановки строк 2 и 4 даны на рис. 8.2, перестановка столбцов 1 и 2 - на рис. 8.3.
2. Умножение строк и столбцов на постоянные множители:
а) умножение строки с номерам r на постоянный множитель c:
for j:=1 to m do a[r,j]:=a[r,j]*c; {проход по всем столбцам от 1- m, умножение элементов }
б) умножение столбца с номером p на постоянный множитель c:
for i:=1 to n do a[i,p]:=a[i,p]*c:= {проход по всем строкам от 1- n, умножение элементов }
Для матрицы с рис.8.1 результат умножения ее строки 2 на множитель 1,5 дан на рис. 8.4.
3. Прибавление (вычитание) из одной строки другой, умноженной на постоянный множитель:
а) прибавление к строке с номерам r строки с номером s, умноженной на постоянный множитель c:
for j:=1 to m do a[r,j]:=a[r,j]-a[s,j]*c; {проход по всем столбцам от 1- m, сложение}
б) вычитание выполняется аналогично с заменой “+” на “-”.
Для матрицы на рис.8.1 результат вычитания из строки 1 строки 2, умноженной на 3, дан на рис. 8.5.
4. Транспонирование матриц – операция, при которой ее строки и столбцы меняются местами:
транспонирование матрицы a[1..n,1..m], результат - в матрице b[1.. m,1..n]:
for i:=1 to n do
for j:=1 to m do b[i,j]:= a[j,i];
Для матрицы с рис.8.1 транспонированная матрица дана на рис. 8.6.
5. Сложение (вычитание) матриц – операция, при которой элементы новой матрицы являются суммой (разностью) соответствующих элементов исходных матриц:
определение матрицы с[1.. m,1..n] – суммы матриц a[1..n,1..m] и b[1..m,1..n]:
for i:=1 to n do
for j:=1 to m do с[i,j]:= b[i,j]+a[j,i];
-11 | -23 | -29 | -59 | -4 | |||||||||
-6 | -15 | -68 | -27 | -11 | -14 | ||||||||
-14 | -84 | -14 | -84 | -23 | -68 | ||||||||
-68 | -27 | -4 | -10 | -10 | -84 | -27 |
Рис.8.4 Рис. 8.5 Рис. 8.6
Пример 8. Ввести с клавиатуры элементы квадратной матрицы A[1..3,1..3] с элементами типа integer. Из A получить матрицу В, в которой вместо столбца, содержащего минимальный элемент матрицы A, вставлена строка, содержащая максимальный элемент A. Номера строки с максимальным элементом, столбца с минимальным элементом и матрицу В выдать на экран.
Решение. Обозначим номер строки с максимальным элементом A через Str_max, номер столбца с минимальным элемента - через Stl_min, текущие значения максимума и минимума – через max, min. Коды операторов для ввода элементов матрицы с клавиатуры и вывода ее на экран совпадают с примером 7 с учетом изменения числа строк, поэтому в решении они не приводятся. После ввода матрицы A и ее исходного вывода на экран вначале определяются номера Str_max и Stl_min. Затем производится пересылка A в В и требуемая коррекция матрицы В.
var a,b:array[1..3,1..3] of integer;
i,j,max, min,Stl_min,Str_max,c:integer;
Begin
…/// ввод элементов матрицы с клавиатуры и вывода ее на экран - по примеру 7
Str_max:=1; Stl_min:=1; max:=a[1,1]; min:=a[1,1]; {начальные присвоения значений}
for i:=1 to 3 do {поиск номеров: Str_max- строки с макс.эл. и Stl_min столбца с мин. эл.}
for j:=1 to 3 do begin
if a[i,j]<min then
begin min:=a[i,j];Stl_min:=j end; {поиск столбца с минимальным элементом}
if a[i,j]>max then
begin max:=a[i,j];Str_max:=i end {поиск строки с максимальным элементом}
End;
writeln(' Stl_min=',Stl_min,' Str_max=',Str_max); {вывод номеров столбца и строки}
В:=A; {начальное формирование матрицы В }
for i:=1 to 3 do
b[i,Stl_min]:=a[Str_max,i]; {коррекция матрицы В }
for i:=1 to 3 do begin {вывод результирующей матрицы В }
for j:=1 to 3 do write(' b[',i,',',j,']=',b[i,j]:8); {вывод строки элементов}
writeln; {переход на очередную строку}
End;
End.
Наряду с рассмотренными выше в линейной алгебре рассматривается еще целый ряд других операция с матрицами - умножение их на вектор, на матрицу, расчет определителя, определение обратной матрицы и т.д.
Вопросы для проверки знаний.
1. Как располагаются элементы двумерного массива в памяти?
2. На какое место в памяти, начиная с начала записи массива а(10´10), попадет его элемент a[8,5]?
3. Какие матрицы называют квадратными?
4. Что называют главной диагональю квадратной матрицы?
5. Как можно перечислить все элементы главной диагонали при помощи одного цикла?
6. Какое преобразование матрицы называют транспонированием?
Практические задания.
1. Разработать и отладить код программы, в которой:
а) вводятся с клавиатуры значения элементов целочисленной матрицы A[1..3,1..3],
б) матрица выводится на экран,
в) определяется максимальный элемент матрицы, который затем прибавляется ко всем элементам в нечетных столбцах матрицы,
г) новая матрица выводится на экран.
Динамические массивы
Необходимость работы с большими по числу элементов массивами явилась главной причиной для разработки методов работы с дополнительной динамической памятью. Одним из ее основных результатов явился тип данных "указатель", который в двух словах (по два байта каждое) содержит адрес одиночной величины или массива. Этот тип рассмотрен в Главе 3. Указатель на адрес величины a получается путем использования префикса ^ перед ней: ^ a. Для засылки в указатель адреса уже существующей переменной применяют операцию получения адреса переменной (префикс @ перед ее именем или обращение к функции addr()), для обращения к значению переменной, адрес которой хранится в указателе, к нему примеряется операция разыменования, обозначаемая при помощи суффикса ^.
Выше были рассмотрены обычные массивы, у которых размер устанавливается при описании и не изменяется при выполнении программы, при этом фактически для работы может использоваться не все описанное количество элементов. Такие массивы называют статическими. Данный тип массивов всегда существовал в Паскале. Он удобен при относительно небольших числах элементов в массиве. Если переменная является статическим массивом, то она является хранилищем его данных и имеет размер, равный произведению количества элементов на их размер.
В отличие от статических, динамическими называют массивы, размер которых может изменяться во время исполнения программы. С одной стороны, это дает возможность работать с массивами, не ограничивая заранее их размер предельными объёмами. С другой стороны, более рационально используется память вычислительного устройства за счет выделения массивам реально необходимых ее объёмов. Динамические массивы появились в более поздних версиях Паскаля, с появлением Delphi 4. В отличие от статического случая, переменная динамического массива не содержит все элементы массива, а является указателем на область в памяти, где лежат данные элементы, т.е. на первый элемент массива. Использование динамических массивов освобождает от непосредственного использования указателей в простейших случаях работы с динамической памятью.
Для поддержки работы с динамическими массивами в языке программирования должны быть соответствующие операторы, встроенные функции, добавлены новые возможности прежним операторам.
Как и для обычных массивов, описание динамического массива можно задать при помощи предварительного описания типа (указывается имя динамического массива и тип элементов – один из базовых типов), можно без него - непосредственно при описании переменной. Оба вида описания динамического массива подобны описанию статического с той разницей, что не указывается размерность. Для многомерных массивов также допускается вложенность.
Пример 1. Описания динамических массивов:
typeT1DByteArray: Array of Byte; {Предварительное описание одномерного динамического массива байтовых величин} T1DIntArray = array of integer; {Предварительное описание одномерного динамического массива целых величин} T2DStringArray: Array of Array of string; {Предварительное вложенное описание двумерного динамического массива строковых величин} var
B: T1DByteArray; {Присвоение переменной B типа одномерного динамического массива байтовых величин T1DByteArray } StringMas: T2DStringArray; {Присвоение переменной StringMas типа двумерного динамического массива строковых величин T2DStringArray } Ar_Int:array of integer; {Непосредственное описание переменной Ar_Int как одномерного динамического массива целых величин}
При объявлении динамического массива место под него не отводится. Переменная динамического массива представляет собой обычный указатель (4 байта) на начало массива. Если массив еще не объявлен либо количество элементов в нем равно 0 (массив пуст), то переменная равна nil.
Если динамический массив не пуст, то его действительный размер всегда на 8 байт больше того пространства памяти, которое занимают его элементы за счет двух дополнительных 4-байтовых величины. Сразу перед данными (по отрицательному смещению -4) в памяти помещается индикатор количества элементов в массиве. Перед ним (по смещению -8) находится счетчик ссылок на массив. Этот счетчик ссылок позволяет иметь несколько переменных, ссылающихся на одни и те же данные в массиве и не заботиться об управлении памятью. Компилятор самостоятельно следит за доступом к данным и при уменьшении счетчика ссылок до 0 освобождает всю память массива. Нумерация элементов в динамических массивах, в отличие от статических, начинается с 0 (как в языке С).
Присваивание динамических массивов вида Array_A:= Array_B по аналогии со статическими возможно, когда:
1) оба массива описаны как динамические и имеют одинаковый тип элементов,
2) размер массива Array_A не превышает (больше либо равен) размеру Array_B, либо Array_A=nil.
При выполнении присваивания динамических массивов они имеют общую память и изменения значений элементов в одном массиве приводят к таким же изменениям и во втором. Если затем над одним из массивов выполняются преобразования, меняющие его структуру, то такая общность значений элементов теряется и связь значений элементов массивов утрачивается. Присвоение динамического массива статическому компилятор запрещает, для этого необходимо использовать поэлементную запись из динамического в статический массив.
Удалить динамический массив можно несколькими способами: применением функции Finalize или установкой нулевой длины массива.
Помимо возможности описания массивов без указания их размерности, в Паскале введены следующие основные функции для работы с динамическими массивами:
1) SetLength (mas, number) - устанавливает новый размер массива mas равным number (число элементов);
2) Length (mas) - возвращает количество элементов в массиве mas;
3) Low (mas) _- возвращает индекс первого элемента в массиве mas (всегда 0 для динамических массивов);
4) High (mas) - возвращает индекс последнего элемента в массиве mas;
5) Copy(mas, start_imdex, number) - возвращает подмножество из number элементов массива mas, начиная с номера start_imdex;
6) Slice - используется при передаче динамического массива в процедуры в качестве открытого массива (open arrays).
Сразу после объявления динамический массив пуст. Для работы с ним необходимо задать число элементов в нем с использованием функции SetLength. При повторном применении SetLength кмассиву его размер изменится. Если новое значение размера больше предыдущего, то а нем сохраняются все прежние значения и в конце добавляются новые нулевые элементы. Если новый размер меньше предыдущего, то массив обрезается до нового размера.
Пример 2. Задание длины массива Ar_Int из примера 1:
SetLength(Ar_Int,10);
В результате в массиве будет задано 10 элементов - от Ar_Int [0] до Ar_Int [9].
Обращение к первому элементу динамического массива Dyn_Ar имеет вид Dyn_Ar[0] или Dyn_Ar[Low (Dyn_Ar)].
Пример 3. Обнуление всех элементов динамического массива Dyn_Ar типа integer: FillChar(Dyn_Ar [0],Length(Dyn_Ar)*sizeof(integer)); При работе с динамическими, как и статическими массивами необходимо следить, чтобы номера элементов в массивах не выходили за текущие их границы. Иначе компилятор прекращает выполнение программы с выдачей сообщения об ошибке.Пример 4 с использованием динамических массивов А,В и статического С:
var A,B: array of integer;
C: array[0..10] of integer;
Len, i: Integer;
Begin
Len:=4; SetLength (A,Len);//Создание дин. массива А(0,0,0,0)
for i:=0 to Len-1 do A[i]:=2*i;// Создание дин. массива А (0,2,4,6)
B:=A;// Копирование дин. массива А (0,2,4,6) в дин массив В
for i:=0 to Len-1 do C[i]:=A[i];// Засылка значений в стат. массив С: C(0,2,4,6)
A[1]:=10;//Изменение значения первого элемента массива А: A[1]:=10
writeln (' Enter values of massiv elements:');
for i:=0 to Len-1 do
writeln (' A[',i,']=',A[i], ' B[',i,']=',B[i], ' C[',i,']=',C[i]);
A:=Copy(A,1,2);//Запись в 2 первых элемента (А[0],A[1]) массива А прежних значений А[1], A[2]
writeln (' Finish values of massiv elements:');
for i:=0 to Len-3 do
writeln (' A[',i,']=',A[i],' B[',i,']=',B[i], ' C[',i,']=',C[i]);
SetLength(A,0); SetLength(B,0); //Удаление динамических массивов А и В
End.
B итоге работы программы на экране пользователя выдается информация:
Первая выдача значений элементов массивов показывает, что присвоение B:=A в начале задает полную идентичность динамических массивов A и B - изменение A[1]:=10 автоматически вызвало такое же изменение в массиве В[1]:=10. Статический массив, в который поэлементно были засланы элементы A, не изменился.
Вторая выдача значений массивов показывает, что применение функции Copy к массиву A вызвало разрыв связи динамических массивов A и B.
8.6.1. Двумерные динамические массивы
Обычно для создания и работы с двумерными динамическими массивами (матрицами) используют указатели. Однако применение взаимно однозначных отображений элементов матрицы на соответствующий линейный массив позволяют свести все действия с динамическими матрицами к действиям на линейных векторах, которые являются обычными динамическими массивами.
Рассмотрим матрицу М[1..n,1..m] и соответствующий ей вектор L[0..n×m-1]. Взаимно однозначное отображение множества Мnm пар индексов (i,j) элементов матрицы (у которых 1≤ i ≤ n, 1≤ j ≤ m) на множество Lk значений индекса k элементов L[0≤ k ≤n×m-1], задаваемое функцией
k = k (i, j, m) = (i-1)m +(j-1),
означает, что каждой паре (i,j) из Мnm соответствует единственное значение k. из Lk и наоборот, каждому значению k. из Lk соответствует ровно одна пара (i,j) из Мnm.
Использование функции k = k (i, j, m) позволяет свести работу с динамическими матрицами к работе с обычными одномерными динамическими массивами.
Пример 5. Разработать программу, в которой выполнялись бы следующие действия:
1) ввод с клавиатуры размерности квадратной целочисленной матрицы M[1..n,1..n], затем - коэффициентов матрицы,
2) построчный вывод матрицы M[1..n,1..n] на экран,
3) определение в M[1..n,1..n] суммы всех элементов на главной диагонали,
4) исключение из строк M[1..n,1..n] всех элементы, стоящих на главной диагонали,
5)) построчный вывод новой матрицы N[1..n,1..(n-1)] на экран,
6) удаление динамических массивов, соответствующих M и N.
Решение. Обозначим номера строк и столбцов матриц через i и j, динамические линейные массивы, соответствующие матрицам, через LM,LN. При удалении диагональных элементов использовано следующее их свойство: в линейном массиве они лежат с промежутками в n элементов. При выборочной записи элементов массива LM в массив LN использованы их текущие номера n_elM и n_elN.
var LM,LN: array of integer; { Описание дин. массивовLM,LN }
n,i,j,el,S,n_elM,n_elN: integer;
function k(i,j,m:integer):integer; {функция для расчета k = k (i, j, m) = (i-1)m +(j-1) }
begin k:= (i-1)*m + j -1; end;
Begin
writeln (' Vvedite razmernost:');read(n); {запрос на ввод и ввод размерности n }
SetLength (LM,n*n); { Создание дин. массиваLMдля ввода матрицы M[1..n,1..n] }
for i:=1 to n do {ввод элементов матрицы с клавиатуры}
for j:=1 to n do begin
writeln('vvedite element M[',i,',',j,']='); {запрос на ввод элемента M [i,j] }
read(el); LM[k(i,j,n)]:=el; {ввод элемента M [i,j] в линейный массив LM }
End;
for i:=1 to n do begin {вывод матрицы M[1..n,1..n] на экран}
for j:=1 to n do write(' M[',i,',',j,']=',LM[k(i,j,n)]:6); {вывод строки}
writeln; {переход на очередную строку}
End;
S:=0; {расчет суммы S диагон. эл-тов матрицы M[1..n,1..n]}
for i:=1 to n do S:=S+LM[k(i,i,n)];
writeln(' Sum of diagonal ejements=',S); {вывод суммы диагональных элементов M}
SetLength (LN,n*(n-1)); { Создание дин. массиваLNдля ввода матрицы N [1..n,1..(n-1)] }
n_elM:=-1;n_elN:=-1; {За дание начальных значений номерам элементов в дин. массивахLM,LN }
for i:=1 to n-1 do begin { Проход по промежуткам между диаг. эл-тами }
n_elM:= n_elM+1; for j:=1 to n do begin n_elM:= n_elM+1; n_elN:=n_elN+1;
LN[n_elN]:=LM[n_elM] { Засылка значений в динамический массив N [1..n,1..(n-1)] }
End end;
for i:=1 to n do begin { Печать динамического массива N [1..n,1..(n-1)] }
for j:=1 to n-1 do write(' N[',i,',',j,']=',LN[k(i,j,n-1)]:6); {вывод строки}
writeln; {переход на очередную строку}
End;
SetLength(LM,0); SetLength(LN,0); //Удаление динамических массивов LM и LN
End.
По аналогии с рассмотренным выше взаимно однозначным отображением k(i, j, m) = (i-1)m +(j-1),множества пар индексов (i,j) элементов двумерного массива (матрицы М[1..n,1..m]) на множество Lk значений индекса k элементов L[0≤k≤n×m-1], можно организовать взаимно однозначные отображения на линейный массив и массивов более высокой размерности. Например, для трехмерного массива М[1..n,1..m,1..p] взаимно однозначное отображение k(i, j, s, m,р) множества троек индексов (i,j,s) на множество Lk значений индекса k элементов L[0≤ k ≤n×m×р-1] имеет вид:
k = k(i, j, s, m,р) = (i-1)×m×р + (j-1) ×р + (s-1).
Вопросы для проверки знаний.
1. Какие массивы называют статическими, а какие - динамическими?
2. Назовите два вида описания динамических массивов?
3. Чем принципиально отличается объявление динамического массива от статического с точки зрения появления новых объектов в памяти?
4. Какое предварительное действие необходимо выполнить после объявления динамического массива для того, чтобы работать с его элементами?
5. Как переписать динамический массив в статический?
6. Как удалить динамический массив путем изменения его длины?
7. Каким образом можно использовать для работы с многомерными массивами аппарат динамических массивов без использования указателей?
Практические задания.
1.Разработать программу, в которой выполнялись бы следующие действия:
а) ввод с клавиатуры размерности n линейного целочисленного динамического массива L[1..n] и его элементов,
б) расчет суммы элементов массива L[1..n] с выводом ее на экран,
в) удаление динамического массива L[1..n].
2. Разработать программу, в которой выполнялись бы следующие действия:
а) ввод с клавиатуры размерности квадратной целочисленной матрицы M[1..n,1..n], затем - коэффициентов матрицы,
б) построчный вывод матрицы M[1..n,1..n] на экран,
в) смена местами в M[1..n,1..n] первого и последнего столбца,
г) построчный вывод новой матрицы M [1..n,1..(n-1)] на экран,
д) удаление динамического массива, соответствующего M.