Массивы определение описание размещение в памяти использование работа с массивами delphi
Иногда, начиная решать задачу, мы только приблизительно можем предполагать, какой объём данных нам надо сохранить в массиве.
Возникает ситуация, когда приходится лавировать между экономией памяти (а её надо всегда экономить) и желанием сделать массив как можно больше, чтобы гарантированно разместить в нём все данные).
В таком ситуации на помощь приходят динамические массивы. Принцип их применения состоит в следующем.
Задаем первоначальную длину массива. Если в процессе решения задачи массива не хватит, то переопределяем его размер. При этом значения из старого массива переписываются в новую область памяти.
Старя область памяти, занимаемая массивом, освобождается.
Надо помнить, что если массив большой (а он в Delphi может занимать до 2Гб), то на его перезапись требуется достаточно много времени. Если такую операцию выполнять излишне часто, то время на выполнение вычислительного процесса заметно увеличивается.
Работа с массивами
Чтобы получить/изменить значение, хранящиеся в ячейки массива, необходимо указать индекс интересующего элемента
Если массив Delphi имеет размерность больше единицы, например 2, то указывать нужно два индекса
Обращение к элементам двумерного массива чем-то напоминает игру в морской бой. Чтобы проверить есть ли корабль в клетке, нам нужно знать его координаты по ширине и высоте. Вот и индексы в матрице можно сравнить с координатами в морском бое.
Будьте внимательны и при обращении к элементам массива Delphi не выходите за границы. Это инициирует ошибку.
Рассмотрим для начала, как организовать и использовать двумерный массив, в частности двумерный массив строк.
В предыдущем занятии мы рассмотрели, как создать в delphi одномерный массив чисел для хранения значений целого типа (Одномерные массивы в delphi)
Объявим теперь массив, хранящий строковые значения.
и заполним его такими, например, значениями:
А теперь поставим задачу: надо создать массив, в котором будем хранить значения, записанные в ячейках таблицы. Например:
Таблица 1
Инициация трёхмерного динамического массива с различной мощностью по измерениям
Отличительной особенностью динамического массива от статического состоит в том, что количество элементов по каждому индексу (измерению) может быть разным (разная мощность по измерению).
Пусть, например, задан трехмерный массив.
Тогда в общем виде обращение к элементу (ячейке) массива будет:
Будем инициировать массив по следующей схеме (дерево индексов), начиная отсчёт индексов с «0»:
Или в табличном виде:
Таблица 1
Инициируем массив vArr[i,j,k] по левому индексу i:
Инициируем массив по индексу j при i=0:
и при i=1:
Как видим, размерности по второму индексу разные!
И, наконец, инициация по третьему индексу k:
Далее заполняем элементы массива значениями:
Попробуйте сами создать программу, в которой создаётся, заполняется и выводится в компонент Tmemo рассмотренный выше массив.
Объявление массива
Массив, как и любая переменная программы, перед использованием должен быть объявлен в разделе объявления переменных. В общем виде инструкция объявления массива выгладит следующим образом:
- имя — имя массива;
- 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 ;
Типичными операциями при работе с массивами являются:
- вывод массива;
- ввод массива;
- поиск максимального или минимального элемента массива;
- поиск заданного элемента массива;
- сортировка массива.
Заключение.
В этом занятии мы познакомились с многомерными массивами. Рассмотрели принципы их индексации. Заполнили двух и трёхмерные массивы данными. Узнали, что такое динамический массив и заполнили его данными. Отметили, что мощность массива по каждому индексу может быть разной. Привели пример инициализации и заполнения динамического массива данными.
Объявление массива
Перед тем, как использовать массив в Delphi, его необходимо объявить. Делается это следующим образом:
Пример объявления массива из десяти целочисленных элементов
Обратите внимание, что отсчет в массивах принято начинать с нулевого элемента. Хотя никто не запретит вам начать счет с единицы.
В Delphi массив можно задать как константу, иногда это может быть очень полезно:
Инициация одномерного динамического массива.
Конкретная размерность (мощность) массива задаётся с помощью стандартной функции.
В delphi имеется большой набор стандартных функций для решения широкого круга задач.
С двумя из них мы уже познакомились. Это StrToInt() и IntToStr(). Первая преобразуют строку в целый тип данных, а вторая целый тип преобразует в строку.
Теперь воспользуемся стандартной функцией SetLength(), чтобы установить длину массива.
Например, массив длиной 5 элементов определяется так:
SetLength(vArr1,5); (индекс массива будет лежать в пределах от 0 до 4 и сможет быть равным 0, 1, 2, 3, 4)
Уничтожение динамического массива
Чтобы освободить память, занимаемую массивом, нужно использовать ключевое слово nil:
Массив с тремя измерениями
Аналогично можно определить трехмерный массив строк.
Обращение к ячейке трёхмерного массива будет иметь вид: vArr[2,1,3].
Элементы массива целого типа
Значения, хранящиеся в массиве, называются элементами массива.
Рассмотрим пример. Пусть нам надо хранить десять целых чисел. Можно поступить так: объявить десять переменных типа Integer. А если их сто, тысяча, миллион?
Имеется более элегантная возможность. Значения располагают в памяти одно за другим. Запоминают адрес первого числа, а потом указывают, на каком месте последовательности стоит то число, которое надо прочитать.
В терминах delphi это выглядит так. Объявляется тип данных array с помощью ключевого слова type :
Далее объявляется переменная типа TArray следующим образом:
Можно объявить переменную-массив и обычным образом:
Однако первый способ предпочтительнее.
Объявляя переменную «massiv» типа array, мы тем самым декларировали, что будем хранить цепочку из пятнадцати целых чисел.
Выше мы говорили, что обратится к конкретному элементу массива можно по его индексу.
Например, если «у» является переменной целого типа, то справедливо выражение:
Индекс массива
Мы уже использовали в качестве индекса массива целые числа.
Но в качестве индекса можно использовать переменную целого типа. Это исключительно удобно при обработке массива в цикле.
Объявление динамического массива.
Динамический массив объявляется следующим образом:
одномерный динамический массив:
Двумерный динамический массив:
Видео. Программа обработки массива.
Задача: сформировать массив для хранения значений из таблицы 1. Сформировать из данных, хранящихся в массиве, одну строку и отобразить её в компоненте memo.
Объявим тип «массив» с двумя измерениями (двумерный массив):
Задаём начальное значение переменной s:
Формируем строку для вывода в memo:
Используем свойство «text» объекта memo1.Lines:
Создание программы представлено на видео.
Заключение.
Рассмотрено создание двумерного статического массива на примере массива строкового типа. Дана общая формула создания многомерного массива и приведён пример трехмерного массива.
Во втором занятии мы рассмотрели несколько типов переменных: char, string, integer и double. Для решения простых задач этого уже достаточно. Но на практике требуется значительно большее разнообразие типов переменных.
Рассмотрим ещё один тип данных — массив. Собственно, в delphi 7 массив это даже не отдельный тип данных, а просто способ хранения некоторого количества данных одного типа.
Данные в массиве хранятся в последовательной цепочке байт. Адрес первого байта записывают в переменную, называемую именем массива.
Элементы массива пронумерованы. Эти номера называются индексом элемента. Если, например, имя массива будет vArr и массив хранит 10 элементов, то обращение к восьмому элементу будет иметь вид: vArr[7].
Как происходит обращение к элементу массива? Мы сказали, что адрес первого байта массива хранится в переменной массива. Если, например, массив хранит элементы целого типа integer, то под каждый элемент отводится 4 байта.
Почему индекс равен 7, а не 8? Это происходит из-за того, что первый элемент массива всегда имеет номер 0.
Очевидно, что для массива мощностью 10 элементов допустимые номера индекса от 0 до 9.
Если ввести другое значение индекса, то компилятор Delphi выдаст ошибку.
Посмотрим, как вычисляется адрес элемента массива с номером i.
Если адрес первого байта массива равен n, то адрес элемента с индексом i будет равен n+i*4. При i:=0 мы попадаем в начала массива, при i:=1 сдвигаемся на 4 байта и попадаем в начало первого элемента, и так далее.
ЗАКАЗАТЬ
Ввод массива
Под вводом массива понимается процесс получения от пользователя (или из файла) во время работы программы значений элементов массива,
"Лобовое" решение задачи ввода элементов массива — для каждого элемента массива создать поле ввода. Однако если требуется ввести достаточно большой массив, то такое решение неприемлемо. Представьте форму, например, с десятью полями редактирования!
Очевидно, что последовательность чисел удобно вводить в строку таблицы, где каждое число находится в отдельной ячейке. Ниже рассматриваются два варианта организации ввода массива с использованием компонентов StringGrid И Memo.
Под вводом массива понимается процесс получения от пользователя (или изфайла) во время работы программы значений элементов массива,"Лобовое" решение задачи ввода элементов массива — для каждого элемента массива создать поле ввода. Однако если требуется ввести достаточно большой массив, то такое решение неприемлемо. Представьте форму, например,с десятью полями редактирования! Очевидно, что последовательность чисел удобно вводить в строку таблицы,где каждое число находится в отдельной ячейке. Ниже рассматриваются два варианта организации ввода массива с использованием компонентов StringGrid И Memo.
Использование компонента StringGrid
Для ввода массива удобно использовать компонент StringGrid. Значок компонента StringGrid находится на вкладке Additional (рис. 5.2).
Компонент 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, используйте следующий код:
delphi массив строк
Посмотрим, как создаётся массив строк.
Вывод массива
Под выводом массива понимается вывод на экран монитора (в диалоговое окно) значений элементов массива.
Если в программе необходимо вывести значения всех элементов массива, то для этого удобно использовать инструкцию for, при этом переменная счетчик инструкции for может быть использована в качестве индекса элемента массива.
В качестве примера на рис. 5.1 приведено диалоговое окно приложения, которое демонстрирует инициализацию и процесс вывода значений элементов массива в поле метки. Программа выводит пронумерованный список футбольных команд. Следует обратить внимание, что для того чтобы список команд выглядел действительно как список, свойству Label1.AutoSize нужно присвоить значение False (присвойте свойству Label1.Autosize значение True и посмотрите, как будет работать программа). Текст программы приведен в листинге.
Листинг. Инициализация и вывод массива
Инициация двумерного динамического массива
Немного сложнее инициировать двумерный массив.
Пусть надо создать массив размерностью 4 х 6. Порядок инициации будет таким:
Сначала инициируем первый индекс:
Затем инициируют второй индекс:
Обмен данными между массивами
Обменяться данными между переменными очень просто. Достаточно поставить оператор равенства между переменными. Например, x:=y; (оператор равенства — выражение «:=»).
Так же можно поступить и с массивами, но при соблюдении определённых условий. Если мы объявим массив одним из двух способов:
Заполнение компонента TMemo с помощью оператора цикла for и условного оператора if.
Используем следующие соображения.Используем следующие соображения.
Левый индекс i изменяется от 0 до 1.
Индекс j изменяется в зависимости от значения i. При i=0 максимальное значение j=2, при i=1 максимальное значение j=1.
Правый индекс обозначим k. При i=0 и j=0 → максимальное значение k=3, при i=0 и j=1 максимальное значение k=1 и так далее.
Обозначим максимальное значение по индексу j через jj, а по индексу k через kk.
В результате получим следующую таблицу:
Здесь мы ввели в рассмотрение новый оператор — оператор условия, или условный оператор. Этот оператор работает следующим образом.
В круглых скобках записано условие, которое проверяется на истинность.
В первой строке имеем (i=0). Обратите внимание, что при проверке условия двоеточие после переменной не ставится!
Переменная i может принимать различные значения. Но только при i=0 выполнится выражение, стоящее после ключевого слова then. Во всех остальных случаях строка с оператором if пропускается и выполнение программы продолжается со следующего оператора.
После ключевого слова then могут стоять операторные скобки begin … end; Аналогично сказанному выше, записанный в них код или выполняется, или игнорируется в зависимости от того, будет ли выполнено условие.
Таким образом мы формируем предельное значение по индексу j в зависимости от значения i и предельное значение по индексу k в зависимости от сочетания значений i и j.
Определение массива
Массив — набор однотипных переменных, расположенных в памяти непосредственно друг за другом, доступ к которым осуществляется по индексу (индексам). Это общее определение из Википедии. Если говорить о Delphi, то переменные действительно должны быть одного типа. Но есть языки программирования, например php, где поддерживаются г етерогенные массивы (элементы которого могут относиться к разным типам). В самом простом случае массив имеет фиксированное количество элементов, но бывают и димамические массивы, меняющие свою размерность в ходе выполнения программы.
Правило «счётчика»
При заполнении массива надо придерживаться правила счётчика такси.
Заполняя массив, увеличиваем сначала правый индекс. Затем, увеличив на 1 индекс левее, опять прокручиваем правый индекс. И так далее.
Расположение элементов массива в памяти
Если посмотреть на расположение элементов в памяти, то номера ячеек заполняются следующим образом:
Таблица 2
Где n — адрес нулевой ячейки массива.
Тогда элемент vArr[i,j] будет иметь адрес N=n+i*20+j
Пример программы
Составим программу, обрабатывающую трёхмерный динамический массив строк, имеющего различные мощности по индексам.
Объявим тип массива:
В соответствие с таблицей 1 инициируем массив по левому индексу:
По среднему индексу:
По правому индексу:
Выведем построчно элементы массива в компонент memo. Для этого организуем три вложенных цикла:
Элементы массива выводятся в компонент memo построчно:
В качестве индексов используются целочисленные переменные.
Первый цикл for пробегает все допустимые значения для левого индекса.
Далее используем новый оператор — оператор условия, или условный оператор if.
Он функционирует следующим образом. в скобках записано проверяемое условие. Например (i=0). Значение переменной i вычисляется в цикле for. Если значение i действительно равно «0», то выполняется оператор, стоящий за ключевым словом then. Иначе оператор if пропускается и выполняется следующий оаператор.
Запись (i=0) and (j=0) означает, что для выполнения оператора, стоящего после then, требуется одновременное выполнение и условия (i=0), и условия (j=0). Если оба условия возвращают значение «истина» одновременно, то выполняется стоящее в if выражение.
Массивы являются неотъемлемой и очень важной частью любого языка программирования. Язык Pascal не является исключением.
Пример программы работы с массивом
В качестве примера работы с массивом часто решают следующую задачу.
Пусть есть массив целых, например чётных, чисел. Надо вычислить сумму всех элементов этого массива. Предположим, что мощность массива четыре элемента.
Начнём с самого примитивного варианта.
Обратите внимание, что имя типа, как и имя переменной, программист назначает произвольно (какие символы можно использовать в идентификаторах переменных смотри в справочной литературе!).
Объявим переменные и заполним значениями элементы массива.
Далее вычислим сумму значений, хранящихся в массиве.
Но, с расчётом на будущее, лучше вычисление суммы представить в виде следующего алгоритма:
Вычисление суммы происходит следующим образом.
Берётся значение переменной sum, к нему прибавляется значение из ar[2], результат записывается в sum, затирая старое значение. Таким образом на втором шаге мы получаем сумму значений из первого и второго элементов массива. И так далее.
Выше мы говорили, что в качестве индекса можно использовать переменную целого типа. Используя этот факт, приведём классическое решение.
Мы уже неоднократно применяли один из операторов — оператор присваивания «:=» Теперь рассмотрим ещё один оператор — оператор цикла for. Напишем код и рассмотрим, как работает оператор for.
Предварительно введём вспомогательную переменную целого типа:
Оператор for организует цикл, который повторяется заданное число раз.
Начиная своё выполнение, оператор for проверяет значение переменной i.
В нашем примере её начальное значение равно «1» . А в принципе оно может быть задано любым числом.
Также и нижняя граница цикла может быть целочисленной переменной.
Например, i:=n, где n – целочисленная переменная.
Если значение i меньше значения, указанного после ключевого слова to (в нашем случае это 4), то начинается выполняться тело цикла.
Выполнив все строки кода и дойдя до оператора end, управление передаётся оператору for и он увеличит переменную цикла i на единицу.
Потом сравнит её со значением, указанным после to. Если i меньше этого значения, то вновь выполнится тело цикла.
И так до тех пор, пока i не станет больше значения, стоящего после to. Тогда тело цикла больше выполняться не будет, а управление перейдет к выражению, записанному после оператора end; .
Теперь, когда все части решения задачи у нас в руках, продолжим её разработку.
Напишем тело цикла, выполняющего решение поставленной задачи.
Здесь i, пробегая значения от 1 до 4, записывает в элементы массива чётные значения. В итоге будет сформирован массив, элементы которого будут содержать чётные целые числа.
Теперь вычислим суммы всех элементов массива. Запишем:
Замечание. Всё, что написано после «//», является комментарием и не воспринимается delphi как код.
Обратите внимание на очень простое, но очень нужное выражение: sum:=0;
Этим выражение мы задаём начальное значение переменной!
Дело в том, что объявляя переменную, delphi не задаёт её какого-либо начального значения. Поэтому пока мы явно не присвоим ей значения, в ней может содержаться всё, что угодно!
Массив— это структура данных, представляющая собой набор переменных одинакового типа, имеющих общее имя. Массивы удобно использовать для хранения однородной по своей природе информации, например, таблиц и списков.
Хочешь 106 видеоуроков по Delphi в которых я разжевал подробнейшим образом все тонкости программирования на этом языке?
Тогда тебе нужно кликнуть сюда:
Типы массивов в delphi
Не во всех языках программирования строго требуется, чтобы все элементы массива были одного типа.
Поэтому особо подчёркивается, что в delphi массивы являются «типизированными». В ряде случаев нетипизированные массивы более удобны и позволяют решать задачу более элегантно. Но одновременно они наряду с дополнительными удобствами привносит и свои трудности. Нетипизированные массивы могут быть источниками трудно определяемых ошибок.
Массивы подразделяют на одномерные и многомерные.
Например, для хранения данных из таблицы применяют в delphi двумерный массив. Обращение к элементу двумерного массива будет выглядеть, например, следующим образом: vArr[2,7].
Или в общем виде vArr[i,j]. Индекс i ассоциируют с номером столбца, а j — с номером строки.
Аналогично определяются массивы трёх и более измерений.
Наконец, имеется особый вид массива, называемый динамическим. Своё название он получил в силу того, что в процессе работы программы можно изменять размерность массива.
Надо ли Вам будет использовать динамические массивы — Вы решите сами по мере усложнения поставленных задач.
Читайте также: