Как сделать копию массива в делфи

Обновлено: 08.07.2024

Массивы являются неотъемлемой и очень важной частью любого языка программирования. Язык Pascal не является исключением.

Определение массива

Массив — набор однотипных переменных, расположенных в памяти непосредственно друг за другом, доступ к которым осуществляется по индексу (индексам). Это общее определение из Википедии. Если говорить о Delphi, то переменные действительно должны быть одного типа. Но есть языки программирования, например php, где поддерживаются г етерогенные массивы (элементы которого могут относиться к разным типам). В самом простом случае массив имеет фиксированное количество элементов, но бывают и димамические массивы, меняющие свою размерность в ходе выполнения программы.

Объявление массива

Перед тем, как использовать массив в Delphi, его необходимо объявить. Делается это следующим образом:

Пример объявления массива из десяти целочисленных элементов

Обратите внимание, что отсчет в массивах принято начинать с нулевого элемента. Хотя никто не запретит вам начать счет с единицы.

В Delphi массив можно задать как константу, иногда это может быть очень полезно:

Двумерные массивы

То, что мы рассмотрели выше - это все одномерные массивы. Но не кто не запрещает нам задавать и большие размерности. Частенько на практике используются двумерные массивы, так называемые матрицы.

Чтобы объявить матрицу в Delphi, используйте следующий код:

Работа с массивами

Чтобы получить/изменить значение, хранящиеся в ячейки массива, необходимо указать индекс интересующего элемента

Если массив Delphi имеет размерность больше единицы, например 2, то указывать нужно два индекса

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

Будьте внимательны и при обращении к элементам массива Delphi не выходите за границы. Это инициирует ошибку.


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

Хочешь 106 видеоуроков по Delphi в которых я разжевал подробнейшим образом все тонкости программирования на этом языке?

Тогда тебе нужно кликнуть сюда:

ЗАКАЗАТЬ

Массивы в Delphi

Объявление массива

Массив, как и любая переменная программы, перед использованием должен быть объявлен в разделе объявления переменных. В общем виде инструкция объявления массива выгладит следующим образом:

  • имя — имя массива;
  • array — зарезервированное слово языка Delphi, обозначающее, что объявляемое имя является именем массива;
  • нижний_индекс и верхний_индекс — целые константы, определяющие диапазон изменения индекса элементов массива и, неявно, количество элементов (размер) массива;
  • тип — тип элементов массива.

Примеры объявления массивов:

temper:array[ 1..31 ] of real ;

koef: array [ 0..2 ] of integer ;
name: array [ 1..30 ] of string [ 25 ];

Специально по теме массивов, чтобы было Вам понятнее я подготовил отдельный видеоурок. Посмотрите его обязательно и сразу поймете как работать с массивами!

При объявлении массива удобно использовать именованные константы. Именованная константа объявляется в разделе объявления констант, который обычно располагают перед разделом объявления переменных. Начинается раздел объявления констант словом const. В инструкции объявления именованной константы указывают имя константы и ее значение, которое отделяется от имени символом "равно". Например, чтобы объявить именованную константу нв, значение которой равно 10, в раздел const надо записать инструкцию: нв=ю. После объявления именованной константы ее можно использовать в программе как обычную числовую или символьную константу. Ниже в качестве примера приведено объявление массива названий команд-участниц чемпионата по футболу, в котором используются именованные константы.


const
ВТ = 15; // число команд
SN = 25 ; // предельная длина названия команды
var
team: array [ 1.. BT] of string [SN];

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

team[ 1 ] := 'Зенит 1 ;

d := koef[l]*koef[l]- 4 *koef[ 2 ]*koef[ 1 ];
ShowMessage(name[n+ 1 ]);
temper := StrToFloat(Editl . text);

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

Имя: array [нижний_индекс. .верхний_индекс] of тип = (список) ;

где список — разделенные запятыми значения элементов массива.

a: array[lO] of integer = ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 );
Team: array [ 1..5 ] of String[ 10 ]=( 'Зенит' , 'Динамо' , 'Спартак' , 'Ротор' , 'СКА' );

for i := 1 to 10 do a:= 0 ;

Типичными операциями при работе с массивами являются:

  • вывод массива;
  • ввод массива;
  • поиск максимального или минимального элемента массива;
  • поиск заданного элемента массива;
  • сортировка массива.

Вывод массива

Под выводом массива понимается вывод на экран монитора (в диалоговое окно) значений элементов массива.

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

В качестве примера на рис. 5.1 приведено диалоговое окно приложения, которое демонстрирует инициализацию и процесс вывода значений элементов массива в поле метки. Программа выводит пронумерованный список футбольных команд. Следует обратить внимание, что для того чтобы список команд выглядел действительно как список, свойству Label1.AutoSize нужно присвоить значение False (присвойте свойству Label1.Autosize значение True и посмотрите, как будет работать программа). Текст программы приведен в листинге.


Листинг. Инициализация и вывод массива


Ввод массива

Под вводом массива понимается процесс получения от пользователя (или из файла) во время работы программы значений элементов массива,

"Лобовое" решение задачи ввода элементов массива — для каждого элемента массива создать поле ввода. Однако если требуется ввести достаточно большой массив, то такое решение неприемлемо. Представьте форму, например, с десятью полями редактирования!

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

Под вводом массива понимается процесс получения от пользователя (или изфайла) во время работы программы значений элементов массива,"Лобовое" решение задачи ввода элементов массива — для каждого элемента массива создать поле ввода. Однако если требуется ввести достаточно большой массив, то такое решение неприемлемо. Представьте форму, например,с десятью полями редактирования! Очевидно, что последовательность чисел удобно вводить в строку таблицы,где каждое число находится в отдельной ячейке. Ниже рассматриваются два варианта организации ввода массива с использованием компонентов StringGrid И Memo.

Использование компонента StringGrid

Для ввода массива удобно использовать компонент StringGrid. Значок компонента StringGrid находится на вкладке Additional (рис. 5.2).

Массивы в Delphi

Компонент strinqGrid представляет собой таблицу, ячейки которой содержат строки символов.

В качестве примера использования компонента stringGrid для ввода массива рассмотрим программу, которая вычисляет среднее арифметическое значение элементов массива. Диалоговое окно программы приведено на рис. 5.3. Компонент stringGrid используется для ввода массива, компоненты Label1 и Label2 — для вывода пояснительного текста и результата расчета, Buttoni — для запуска процесса расчета.


Добавляется компонент stringGrid в форму точно так же, как и другие компоненты. После добавления компонента к форме нужно выполнить его настройку в соответствии с табл. 5.2. Значения свойств Height и width следует при помощи мыши установить такими, чтобы размер компонента был равен размеру строки.

Текст программы приведен в листинге.

Значения свойств компонента StringGrid1

Свойство Значение
ColCount 5
FixedCols 0
RowCount 1
DefaultRowHeight 24
Height 24
DefaultColWidth 64
Width 328
Options.goEditing true
Options.AlwaysShowEditing true
Options.goTabs true

Листинг. Ввод и обработка массива целых чисел

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

Текст процедуры обработки события onkeypress приведен в листинге 5.3. Следует обратить внимание на свойство Col, которое во время работы программы содержит номер колонки таблицы, в которой находится курсор. Это свойство можно также использовать для перемещения курсора в нужную ячейку таблицы. Однако нужно учитывать, что колонки таблицы, впрочем, как и строки, нумеруются с нуля.

Листинг 5.3. Процедура обработки события onkeypress

Если нужно ввести массив дробных чисел (a: array[1. .5] of real), то процедура обработки события onkeypress несколько усложнится, т. к. помимо цифр допустимыми символами являются символ-разделитель (запятая или точка — зависит от настройки Windows) и минус. С целью обеспечения некоторой дружественности программы по отношению к пользователю можно применить трюк: подменить вводимый пользователем неверный разделитель верным. Определить, какой символ-разделитель допустим в текущей настройке Windows, можно, обратившись к глобальной переменной Decimal separator. В листинге 5.4 приведен текст модуля приложения ввода и обработки массива дробных чисел. Процедура обработки события onkeypress обеспечивает ввод в ячейку таблицы только допустимых при записи дробного числа символов.

Листинг 5.4. Ввод и обработка массива дробных чисел

Объявляя статический массив в Delphi, мы указывали его размерность от и до, например [0..3], то есть длина такого массива определена, она конечна и уже не может быть изменена, в этом собственно и заключается статичность массива.

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

Давайте рассмотрим на примере, как все это отражается на синтаксисе. Объявим динамический одномерный массив вещественных чисел:

1) в разделе var просто определяем переменную и ее тип:

2) Для определения размерности, воспользуемся функцией SetLength. Чтобы было понятней, эта функция имеет два параметра. Первый это переменная нашего массива — a, второй — его длина , допустим пусть будет — 5:

Чтобы при необходимости высвободить из по массива память, достаточно прописать:

a:=nil; — nil в Delphi означает отсутствие значения.

Для непосредственной работы с динамическими массивами, существует ряд функций, это:

  • функция Length— определяющая длину массива;
  • функция High— возвращающая наибольший индекс массива;
  • функция Low—возвращающая наименьший индекс массива;

Продемонстрируем теперь на примере, работу функции lehgth и возможность изменения размера массива. Для этого напишем программу, в которой мы в Edit будем вводить желаемый размер массива, и по нажатию кнопки, label нам покажет, что введенный размер, нашему массиву присвоен.

1) Кидаем на форму компоненты Label, Button и Edit;

2) Свойство Caption у label и Text у Edit1 ставим в 0, a в свойстве Caption у Button запишем фразу: — Задать размер;

3) Создаем обрабочик событий OnClick на кнопке, объявляем наш массив и записываем следующий код:

4) Запускаем проект, и убеждаемся, что можем теперь задавать практически любой размер нашему массиву, вводя числа в Edit, и нажимая на кнопку.

Теперь продемонстрируем на примере один из способов задания размера и автоматического заполнения элементов динамических массивов. Напишем программу, в которой в первый Edit, мы будем вводить размер массива, во второй Edit значение его элементов. А по нажатию на кнопку, компонент Мемо — отобразит нам, как размерность массива, так и содержание его элементов.

1) Кидаем на форму 2 компонента Edit, один — Button и один — Memo;

2) В свойстве Text у Edit1 и Edit2 — записываем 0, очищаем свойство Lines компонента Memo, а в свойство Caption у Button запишем слово: — Вычислить;

3) Создаем обработчик событий OnClick на Button, и пишем следующее:

Каковы плюсы и минусы дублирования экземпляра объекта с конструктором или функцией экземпляра?

Одно важное различие сразу приходит в голову - в последнем случае конструктор Create должен быть виртуальным, чтобы иерархия классов, поддерживающая Clone, могла быть построена на основе TMyObject.

Предположим, что это не проблема - что TMyObject и все, что на нем основано, полностью под моим контролем. Каков ваш предпочтительный способ создания конструктора копирования в Delphi? Какую версию вы считаете более читаемой? Когда вы будете использовать прежний или последний подход? Обсудить.:)

EDIT: Моя главная проблема с первым примером заключается в том, что использование очень тяжело по сравнению со вторым подходом, то есть

EDIT2 или "Почему мне нужна однострочная операция"

Я согласен с тем, что Assign - разумный подход в большинстве случаев. Даже разумно реализовать "конструктор копирования" внутри, просто используя назначение.

IOW, я предпочитаю писать

ОТВЕТЫ

Ответ 1

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

Способ Delphi ( TPersistent ) отделяет создание и клонирование:

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

изменить из-за требования oneline Вы можете смешивать его, конечно, используя метаклассы Delphi (непроверенные)

В остальном просто реализуйте свои операторы assign() , и вы можете смешивать несколько способов.

edit2

Я заменил код выше кодом, протестированным в D2009. Существуют некоторые зависимости типов, которые могли бы смутить вас, надеюсь, что это более понятно. Конечно, вам придется изучить механизм назначения. Я также тестировал параметр metaclass=nil по умолчанию, и он работает, поэтому я добавил его.

Ответ 2

Я не думаю, что есть правильный способ, это просто зависит от личного стиля. (И, как заметил Марко, есть еще несколько способов.

  • Метод конструктора короткий, но он нарушает принцип, согласно которому конструктор должен только конструировать объект. Возможно, это не проблема.
  • Способ клонирования является коротким, хотя вам необходимо предоставить вызов для каждого класса.
  • Назначение - это больше Delphi. Он отделяет создание и инициализацию, что хорошо, потому что нам нравится один метод, который позволяет использовать код лучше для поддержания.

И если вы реализуете Assign using streams, у вас есть только одно место, чтобы беспокоиться о том, какие поля должны быть доступны.

Ответ 3

Мне нравится стиль клона, но только на Java (или на любом другом языке GC). Я использовал его несколько раз в Delphi, но в основном я остаюсь с Create и Assign , потому что гораздо яснее, кто несет ответственность за уничтожение объекта.

Читайте также: