Перейти к содержимому

Как задать размер динамической матрицы в lazarus

  • автор:

Динамический или статический?

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

var LettersCount: array ['a'..'z'] of integer;

и работать с ним в свое удовольствие:

LettersCount['z'] := 1; LettersCount['d'] := LettersCount['d'] + 1;

Недостатки таких массивов известны: если заранее неизвестно, сколько элементов потребуется использовать, то под массив отводится память максимального размера. В итоге в большинстве случаев мы «запасаемся впрок», а иногда и этого «запаса» оказывается недостаточно. Именно поэтому такие массивы называются статическими: их размер статичен и должен быть задан на этапе компиляции программы.

В Delphi Object Pascal появились динамические массивы, размер которых можно не только задавать, но и менять по ходу работы программы. Именно об этих массивах и о преимуществах их использования пойдет речь далее.

Описываются они предельно просто:

var a: array of integer;

Чтобы задать размер такого массива, следует вызвать процедуру SetLength:

var n: integer; read(n); SetLength(a,n);

Как мы видим, размер такого массива может быть задан переменной, которая вычисляется по ходу работы програмы (в данном случае ее значение вводится).

Чтобы определить размер динамического массива, следует вызвать функцию Length: Length(a) возвращает размер динамического массива.

Индексы динамического массива — только целочисленные. Кроме того, нижняя граница индекса всегда равна нулю. То есть после вызова SetLength ( a,n ) элементами массива a являются a[0]..a[n-1]. Вот как вывести элементы динамического массива:

for i:=0 to Length(a)-1 do write(a[i],' ');

Чем замечательна процедура SetLength — так это тем, что она может вызываться повторно, и при последующих вызовах старое содержимое массива сохраняется:

SetLength(a,3); a[0] := 666; SetLength(a,5); writeln(a[0]); // выведется 666 

Динамические массивы представляются в памяти ссылками. Это означает, что любая переменная типа «динамический массив» является указателем на непрерывный участок динамической памяти. Первоначально этот указатель хранит nil, а вызов SetLength(a) выделяет под данные массива блок динамической памяти и записывает в a адрес этого блока памяти.

Тот факт, что переменные — динамические массивы — это всего лишь адреса, имеет несколько следствий.

Во-первых, при присваивании статических массивов копируется содержимое, а при присваивании динамических — только указатель:

var a1,a2: array [1..10] of integer; var b1,b2: array of integer; a1 := a2; // копируется содержимое b1 := b2; // копируется указатель

То есть, присваивание больших статических массивов происходит долго, а присваивание динамических — быстро независимо от их размера.

Во-вторых, при присваивании динамических массивов обе пременные b1 и b2 указывают на один участок динамической памяти, поэтому изменение элемента в массиве b1 приводит и к изменению массива b2:

b1[0] := 5; writeln(b2[0]); // выведется 5 

Чтобы создать копию данных динамического массива, необходимо вызвать функцию Copy:

b2[0] := 3; b1 := Copy(b2); b1[0] := 5; writeln(b2[0]); // выведется 3 

Передача динамических массивов в подпрограммы тоже проста:

type IntArr = array of integer; procedure print(a: IntArr); var i: integer; begin for i:=0 to Length(a)-1 do write(a[i],' '); end; var b: IntArr; . print(b);

Передавать динамические массивы по ссылке чтобы исключить копирование массива не имеет никакого смысла — в подпрограмму передается указатель. Динамический массив имеет смысл передавать как var-параметр только в одном случае: если мы отводим в подпрограмме для него память:

procedure CreateAndFill(var a: IntArr; n: integer; fill: integer); var i: integer; begin SetLength(a,n); for i:=0 to n-1 do a[i] := fill; end.

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

procedure Trap(a: IntArr); begin a[0] := 666; end; var b: IntArr; . b[0] := 777; Trap(b); writeln(b[0]); // выведется 666 

Еще в Delphi имеются так называемые открытые массивы. К сожалению, они по внешнему виду очень похожи на динамические:

procedure print1(a: array of integer); var i: integer; begin for i:=0 to High(a)-1 do write(a[i],' '); end;

Смысл в том, что при вызове на место открытого массива можно подставлять статический массив любого размера. Но запись array of integer используется в совершенно другом смысле! Поэтому мы полностью отказались от открытых массивов в PascalABC.NET. Пользуйтесь динамическими массивами!

Посмотрим теперь, что нового появилось в динамических массивах в PascalABC.NET.

1. Динамические массивы можно инициализировать при описании:

var a: array of integer := (1,3,5);

2. Выделять память под динамическе массивовы можно с помощью операции new:

a := new integer[5];

Такой способ хорош тем, что он подчеркивает, что динамический массив в .NET является классом. Плох же он тем, что при повторном выделении памяти таким способом старое содержимое теряется.

3. Как мы упомянули, динамический массив в PascalABC.NET является классом, а значит, он имеет методы и свойства:

a. Length — свойство, возвращающее длину массива
System. Array . Sort ( a ) — статический метод, сортирующий массив a по возрастанию
System. Array . Reverse ( a ) — статический метод, инвертирующий данные в массиве a

и многие другие.

4. Для динамических массивов в PascalABC.NET имеет место структурная эквивалентность типов (в Delphi — именная). Поэтому следующий код в PascalABC.NET будет работать, а в Delphi вызовет ошибку компиляции:

var b1: array of integer; b2: array of integer; . b1 := b2;

5. Ввиду структурной эквивалентности типов для динамических массивов их можно передавать в подпрограмму следующим образом:

procedure print(a: array of integer); begin for var i:=0 to a.Length-1 do write(a[i],' '); end;

Напомним, что открытые массивы в PascalABC.NET отсутствуют!

6. Для динамических массивов (в отличие от статических) можно использовать цикл foreach (при условии, что мы осуществляем доступ к элементам только на чтение):

foreach x: integer in a do write(x,' ');

И, наконец, скажем несколько слов про двумерные динамические массивы. Они моделируются как массивы массивов.

Следующий код иллюстрирует создание двумерного динамического массива размера m на n:

var с: array of array of integer; m,n: integer; . read(m,n); SetLength(с,m); for var i:=0 to m-1 do SetLength(c[i],n);

Новости

20.05.23. На странице https://pascalabc.net/stepikcourse опубликованы новые курсы по PascalABC.NET от центра олимпиадного программирования DL Club.

08.05.23. Вышла версия PascalABC.NET 3.9.0.beta. Основное — ковариантные параметры обобщений, аргументы по умолчанию при вызове подпрограммы, модуль автоматической проверки LightPT.

22.02.23. Открыта регистрация на конференцию «Использование системы программирования Pas​cal​ABC​. NET в обучении программированию»

Copyright © Ivan Bondarev, Stanislav Mihalkovich 2024 All rights reserved. Custom Design by Youjoomla.com

Случайная программа

// Инвертирование массива
// Уровень сложности: 1
procedure Invert(a: array of integer);
begin
var n := a.Length;
for var i:=0 to n div 2 - 1 do
Swap(a[i],a[n-i-1]);
end;

const N = 10;

begin
var a := ArrRandom(N);
Writeln('Исходный массив: ');
a.Println;
Invert(a);
Writeln('После инверсии: ');
a.Println;
// Стандартная процедура
Reverse(a);
Writeln('После второй инверсии: ');
a.Println;
end.

Массивы простые, многомерные и динамические

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

Динамическими называются массивы, при объявлении которых размер не указывается. А во время выполнения программы размер такого массива можно изменять.

Объявляются динамические массивы также в разделе var , следующим образом:

var da: array of integer;

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

SetLength() — устанавливает размер массива. Синтаксис :

SetLength(, );
SetLength(da, 5); //установили размер массива в 5 элементов

Тут следует оговориться, что в отличие от обычного массива, начальный индекс которого может быть любым, индексация динамического массива всегда начинается с нуля. То есть, индексация элементов массива в нашем примере будет от 0 до 4 — всего пять элементов. Как только мы установили размер массива, в памяти выделяется место под него. В нашем примере будет отведено по 4 байта (тип integer ) для 5 элементов массива. Обращаться к этим элементам можно обычным образом:

da[0]:= 5; da[4]:= da[0];

Теперь мы можем прибавить элемент к массиву, установив для него новый размер:

SetLength(da, 6);

В этом случае, один пустой элемент будет добавлен в конец массива. Если же напротив, мы уменьшим его размер:

SetLength(da, 4);

то массив усекается. Если последний элемент содержал какие-то данные, они будут потеряны. Освободить память массива можно, присвоив ему нулевую размерность :

SetLength(da, 0);

Также освободить память можно, присвоив массиву значение nil (ничего, пусто):

da:= nil;

Впрочем, этого можно и не делать: по окончании процедуры, где данный массив был объявлен, память будет освобождена автоматически.

Динамические массивы могут быть и многомерными. Например, двухмерный массив целых чисел можно объявить так:

var a: array of array of integer;

Затем такому массиву можно присвоить размерность , например, 4 на 5:

SetLength(a, 4, 5);

Это будет, как если бы мы объявили простой массив :

var a2: array[0..3, 0..4];

Length() — возвращает размер динамического массива, то есть, количество его элементов. Например, нам нужно посмотреть размер массива, и если он пустой, то добавить в него один элемент:

if Length(da) = 0 then SetLength(da, 1);

Low() — возвращает нижний индекс массива , у динамических массивов это всегда ноль.

High() — возвращает верхний индекс массива , но это не то же самое, что количество элементов. Если у массива 5 элементов, то Length() вернет 5, а High() вернет 4, так как индексация начинается с нуля.

Пример обхода массива от первого до последнего элемента:

for i:= Low(da) to High(da) do da[i]:= i * i;

В примере мы каждому элементу присваиваем квадрат его индекса. Давайте поработаем с динамическими массивами на практике. Чтобы не портить наш конвертер температур, закройте его и откройте новый проект. Мудрить мы не будем — нам нужна только форма и простая кнопка на ней. Переименовывать тоже ничего не будем, это же просто пример. Сохраните новый проект в папку 13-02.

Сгенерируйте процедуру OnClick для кнопки, её код будет таким:

procedure TForm1.Button1Click(Sender: TObject); var s: string; //для запроса da: array of string; //динамический массив строк i: integer; //счетчик begin //узнаем у пользователя, сколько строк делать: s:= '0'; InputQuery('Привет!', 'Сколько строк желаете создать?', s); //если ноль, то ничего не делаем, выходим из процедуры: if StrToInt(s) = 0 then Exit; //иначе устанавливаем указанную размерность массива: SetLength(da, StrToInt(s)); //теперь обойдем весь массив, устанавливая в его элементы значения: for i:= Low(da) to High(da) do da[i]:= 'Строка №' + IntToStr(i + 1); //теперь снова обойдем массив и создадим сообщение из его строк: s:= ''; for i:= Low(da) to High(da) do s:= s + da[i] + #13; ShowMessage(s); end;

Код содержит достаточно подробные комментарии. Вначале в строковую переменную s мы получаем количество желаемых строк. Так как функция InputQuery() возвращает только строку, нам придется получать целое число в виде строки — никакой проверки мы здесь не делаем, это же только демонстрация работы с динамическим массивом. Поэтому правильность вводимого числа оставим на совести пользователя.

Далее, мы проверяем — не ноль ли это? Если строк создавать не нужно, мы просто выходим из процедуры, пропуская весь остальной код. Если же пользователь ввел какую-то цифру, причем она должна быть больше нуля, то мы устанавливаем указанную размерность массива:

SetLength(da, StrToInt(s));

Далее, с помощью цикла for мы обходим весь массив от первого до последнего элемента. В каждый элемент мы записываем строку: » Строка № «, добавляем номер элемента и переход на новую строку. Обратите внимание, для первой строки i будет равно 0, поэтому мы указываем i + 1 :

for i:= Low(da) to High(da) do da[i]:= 'Строка №' + IntToStr(i + 1);

Затем мы очищаем строковую переменную s , чтобы вторично воспользоваться ей, собрать в неё сообщение. Что и делаем в следующем цикле:

for i:= Low(da) to High(da) do s:= s + da[i] + #13;

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

Как задать размер динамической матрицы в lazarus

При изменении размера строки StringToChange, новый размер NewLength может быть меньше, такой же или больше, чем у существующей строки. Во всех случаях размер задается в символах и в любом случае создается новая строка.

Если строка короче, то она отсекается. Если она длиннее, то добавленные символы не будут проинициализированы. Это может дать странный эффект — смотрите первый пример.

Динамический массив объявляется без задания фиксированной длины. Такое объявление создает лишь указатель. Даже многомерный динамический массив создается в виде одного неинициализированного указателя.

SetLength меняет длину измерений Dim1Length, Dim2Length … массива ArrayToChange. Это может быть сделано несколько раз — не только над неинициализированным указателем. Последующие вызовы сотрут данные или добавят дополнительное место. Это дополнительное место инициализируется только в том случае, если оно содержит строки, интерфейсы или переменные типа Variant.

Length Возвращает число элементов в массиве или строке

SetString Копирует символы из буфера в строку

Slice Создает часть массива с параметром «Открытый Массив»

Как задать размер динамической матрицы в lazarus

Дана строка чисел, содержащая пробелы. Количество пробелов может быть произвольным. Сформировать массив чисел

Запустите среду программирования Lazarus (Приложения – Программирование – Lazarus).

Создайте новый проект и сохраните его в новой папке Обработка строк — Проект — Сохранить проект как. ).

1. Создайте форму и разместите на ней компоненты Edit1, Edit2, Label1, Label2, Button1, Button2.

2. Измените значения свойства Caption для Form1, Label1, Labe2, Button1, Button2. Удалите текст из Edit1 и Edit2, изменив свойство Text.

3. Создайте процедуру сброса данных для кнопки Button2 – OnClick:

N:=0; Edit1.Text:=»; Edit2.Text:=»;

4. Добавьте кнопку выхода из программы, процедура OnClick которой состоит из одной команды Close;

5. В разделе описания переменных опишите переменные целого типа N и i, где N – размер массива, i – порядковый номер элемента массива., а также М – массив целых чисел.

var Form1: TForm1;

M:array of integer;

6. Реализуем запрет ввода любых символов в окно Edit1. Для этого выберите в окне Инспектора объектов Edit1 — События — OnKeyPress.

Вставьте в тело процедуры следующий оператор:

7. Для Edit2 вызовите событие OnKeyPress и запретите ввод символов, не являющихся цифрами, минус и пробел разрешаюися

8. Создайте программный код события OnClick для кнопки Button1, учитывая, что нажатие на кнопку Button1 означает конец ввода с клавиатуры, количество введенных чисел должно быть присвоено N и выведено в поле Edit1.

if Edit2.Text[1]in[‘-‘,’0’..’9′]then N:=1 else N:=0;

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *