| |||||
Программируем на Delphi. Структурированные типы. Основы и принципы работыМихаил Новиков, Егор Чухин Вступление.В этой статье будут рассмотрены вопросы, связанные с работой структурированных типов данных. Будет рассказано об основах работы с ними и о применении полученных знаний на практике. Проблемы работы со структурированными типами данных остро стоят перед программистом в наше время. Каждому, кто собрался написать собственную программу, необходимо уметь обращаться с большим объемом однотипной информации, и как раз знания, полученные из этой статьи, в дальнейшем вам очень пригодятся. Наиболее удобным средством программирования, на мой взгляд, является Delphi. В нем-то мы и будем рассматривать действия с типами. Теоретические сведения.Чтобы начать рассказывать о структурированных типах, нужно разобраться, что подразумевается под этим понятием. К структурированным типам можно отнести массивы, записи, множества, файлы (о каждом типе далее будет рассказано более подробно). Любые структурированные типы состоят из других типов, которые могут быть простыми или структурированными, тем самым образуя вложенность одного типа в другой, в этом и состоит весь принцип их образования. Нужно также отметить, что в Delphi глубина вложенности типов является произвольной, то есть программист может использовать нужное ему количество вложенности типов, ограничиваясь только суммарным длиной 2 Гбайт. Теперь перейдем к отдельному разбору каждого из структурированных типов. МассивыМассивы делятся на статический тип и динамический тип. Статические массивы - это такие массивы, число элементов которых не изменяется в процессе выполнения программы. Динамические массивы, в свою очередь, имеют свойство изменять количество элементов на нужное пользователю. Начнем со статических массивов. Они могут быть как одномерными, так и многомерными. Для создания типа нужно вписать в раздел type имя массива, ключевое слово array, индексы и тип компонентов, из которых состоит наш массив, следующим образом: Type <имя массива> = array [<индексы>] of <тип компонентов, составляющих массив>; Для создания же переменной как массива нужно описать эту переменную в разделе Var, не описывая предварительно массива как тип. Это можно сделать следующим образом: Var <название переменной> = array [<индексы>] of <тип массива>; Для примера приведем следующие способы работы со статическими массивами: 1) Объявления массива как тип: Type Number = array [1..100] of Integer; //Будьте внимательны - при указании промежутка //индексов нужно использовать две точки "..". 2) Объявление массива как переменной: Var N1, N2 = array [1..50] of Real; //Для использовании промежутка индексов также //используется две точки "..". 3) Также массивы могут быть двумерными (их еще называют двумерной матрицей): Var Tablica = array [1..20,1..20] of Char; //Чтобы разделить диапазон индексов в // двумерном массиве используется запятая 4) Для объявления переменной описанного нами выше массива-типа Number нужно написать: Var B: Number; // описываются две переменных B и С C: Number; 5) Можно использовать вложенность в массив других стандартных типов: Type Mathematic = array [char] of Byte; 6) Рассмотрим еще один важный прием работы с массивами: Var X1, X2 = array [1..10] of Integer; <Описание других переменных> Begin <работа с массивами X1 и X2> X1:= X2; // Все значения массива X2 присваиваются массиву X1 <последующий код программы> End. Написанный выше пример является правильным приемом работы по присвоению всех значений одного массива другому. Теперь покажем, какую ошибку мог сделать программист: Var X1 = array [1..10] of Integer; X2 = array [1..10] of Integer; <Объявление других переменных, используемых приложением> Begin <Присвоение массивам каких-либо значений> X1:=X2; <Продолжение кода программы> End. Запись неправильна, из-за того что производится попытка присваивания значений массивов разных типов. Появится сообщение об ошибке. Теперь перейдем к разбору динамических массивов. Само понятие динамического массива подразумевает под собой массив, в котором количество обрабатываемых компонентов может изменяться в процессе работы приложения. Границы индексов в таких массивах указывать не нужно. Динамические массивы используются в таких случаях, когда заранее неизвестно количество компонентов и когда идет работа с большим количеством данных и требуется экономия памяти компьютера. Они описываются следующим образом: Var P1, P2: array of Real; В примере описаны два массива типа Real, диапазоны индексов которых не указываются. Но их можно указать в процессе работы самой программы при помощи стандартной функции SetLength (), которая инициализирует количество элементов в массиве: Var M, R: array of Char; Begin SetLength (R, 50); SetLength (M, 100); End. Сразу возникает проблема - если мы указали число компонентов динамического массива функцией SetLength (), то как очистить количество компонентов и записать его заново? Решение очень простое. Очистку массива, то есть освобождение памяти, можно произвести, присвоив ему значение NIL или используя процедуру Finalize(), а запись количества компонентов производится уже известной нам функцией. Можно привести следующий пример: Var Name: array of Char; Begin SetLength (Name, 20); <Действия с массивом> Name:= NIL; // Эту строчку кода можно заменить Finalize (Name); <Продолжение программы> End. Так же, как и статические массивы, динамические могут быть двумерными. Объявление двумерного динамического массива можно записать примерно следующим образом: Var Square array of Integer array of Integer; Присваивание двумерному динамическому массиву длины происходит при помощи той же функции SetLength () вот так: SetLength (Square, 30, 30); В рассмотренной выше строчке кода уже описанному динамическому двумерному массиву Square присваивается размер 30 на 30. Иногда возникает надобность задать длину отдельному столбику массива. Допустим, мы описали двумерный динамический массив F и хотим присвоить каждому столбику разную длину. Вот что для этого надо написать: SetLength (F, 4); // В этой строчке устанавливается количество столбцов SetLength (F [0], 10); SetLength (F [1], 5); SetLength (F [2], 7); SetLength (F [3], 15); Нужно заметить, что, как и в одномерных массивах, индексы двумерных нумеруются с нуля. Говоря о массивах, нужно помнить и о проблеме передачи их в подпрограммы (функции и процедуры) в качестве аргументов. Некоторых начинающих программистов может смутить эта задача, поэтому я и решил описать способы ее решения. Рассмотрим подпрограмму Getwrite, которая должна обрабатывать массив, передаваемый как аргумент. По всем правилам объявления процедуры мы бы написали следующий код: Procedure Getwrite (B: array [1..50] of Byte); Но это было бы ошибкой, так как в аргументе функции содержится тип - диапазон, ограничивающий индексы массива, а нужно указывать в параметрах подпрограммы только стандартный или уже описанный тип. Следовательно, код нужно было писать вот так: Type TPole: array [1..50] of Byte; <последующие операторы> Procedure Getwrite (B: TPole); <собственно, сама процедура> Совершенно по-другому дело обстоит с динамическими массивами. Они могут передаваться в подпрограммы, если аргумент объявлен как открытый массив. Длину передаваемого в процедуру динамического массива можно узнать при помощи функции High, синтаксис ее очень прост: High (<название массива>). Для примера можно привести строки: Var Res: array of Integer; <присваивание Res различных значений и определение его длины> Procedure Result (f: array of Integer) <в этом месте идет код процедуры> Result (Res); //использование процедуры по назначению Необходимо сказать, что в подпрограмму с аргументом, объявленным как открытый массив, можно передавать и статические массивы. Вот и все основные сведения, которые должен знать программист, начинающий работать с массивами. Следующий раздел статьи будет посвящен записям. Краткие сведения о записяхЕсли само понятие массива большинству пользователей понятно, то вот что такое запись, некоторые не знают или знают, но не умеют с ними работать. Для начала разберемся, что же такое запись. Запись представляет собой переменную, которая осложнена тем, что состоит из структуры данных, а структура данных, в свою очередь, состоит из компонентов, которые еще называют полями записи. Нужно заметить, что у каждого поля записи существует свой тип, это позволяет в записях хранить данные разного типа и именно это свойство делает работу с записями очень удобной. Обычно записи объявляют в разделе type, с использованием зарезервированных слов record и end: Type Stud = record Mat, Phis, History: Integer; Name: string; End; Переменные записей можно описать в разделе Var: Var Ivanov, Petrov: Stud; Здесь структура Stud состоит из четырех полей: Mat, Phis, History, которые должны содержать оценки учащихся, и Name, которое должно содержать имя. Заметьте, что в записи присутствуют поля с разными типами. В общем, синтаксис описания записей таков: Type < имя типа> = record <описание полей записи> End. Еще один из плюсов работы с записями состоит в том, что не надо отдельно присваивать поля одной переменной записи другой переменной такого же типа, а можно это сделать одним оператором присваивания: Ivanov := Petrov; А обычная работа с полями осуществляется при помощи обращения к переменной, имеющей тип записи, после которой ставится точка "." и идет название поля. Потом можно производить нужные действия над полем. Синтаксис очень прост: <имя переменной типа записи>.<имя поля> := <значение>; Например: Ivanov.Mat := 4; Petrov.Phis := 5; Иногда требуется, чтобы один тип записи вкладывался в другой. Это может выглядеть следующим образом: Type Rooms = record L, H, S, P: Real; End. И следующим шагом описывается запись, в которой используется для определения типа поля описанный выше тип записи: Type House = record Room1: Rooms; Room2: Rooms; Sale: Integer; End. Var A: House; В этом случае в обращении к полям нужно указывать их через точку: A.Room1.L := 10; A.Room2.P := 68; Лучше бы, конечно, в этом случае использовать оператор with...do, предназначенный для более удобной работы с переменными вложенных записей. На нем мы останавливаться не будем, а только приведем его синтаксис: With <переменная типа записи> do <операторы>; // допустимо использование // блока операторов с использованием begin и end. Множества и с чем их "едят"Множества можно представить как последовательность значений одинакового типа, причем эта последовательность ограничена - количество элементов может изменяться от 0 до 256. Надо особо отметить, что для объявления типа элементам множества нельзя использовать Integer, Word, LongInt и Int64.Тип элементов множества еще называют базовым типом, который обязательно должен быть порядковым (исключения описаны выше). Множественный тип можно объявить таким образом: Type <имя множественного типа> = set of <тип элементов (базовый тип)> Переменные таких типов могут принимать значения любого подмножества базового множества. Что это означает, сейчас расскажу. Объявление множества происходит при помощи конструктора множеств. А конструктор множеств, тем самым, представляет собой последовательность элементов базового множества. В качестве последовательности могут выступать тип - диапазон базового типа, константы и выражения. Допустим, мы описали множество: Type Fly = set of '1'..'100'; объявили переменные этого типа: Var L1, L2: Fly; и присвоили им значения, используя конструктор множеств: L1:= [40..50]; L2:= ['7','9','8','12']; Обратите ваше внимание на то, что последовательность элементов при присвоении значения не играет никакой роли. Также надо бы сказать и о синтаксисе конструктора множеств: <переменная множественного типа> := [ <элементы множества> ]; Для добавления и исключения во множестве значений в процессе работы самого приложения используются процедуры Include и Exclude. Работать с ними можно таким образом: Include (<множество>,<элемент для добавления>); Exclude (<множество>,<элемент для исключения>); Существует большое количество разнообразных действий и операций, которые можно производить над множествами, основными же являются объединение, разность, пересечение. Расскажем о них поподробнее. Будем рассматривать примеры и с числами, и с символами: 1) Объединение - в итоге, после объединения множеств получается одно множество, состоящее из элементов обоих множеств. Заметим, что каждый элемент может входить в получившееся множество только один раз. [1,2,3,4..6] + [3..5,6,12] получается [1,2,3,4,5,6,12] ['A','B','C'] + ['D','E','F'] получается ['A','B','C','D','E','F'] 2) Разность - в итоге этого действия, получившееся множество будет содержать элементы первого множества, которые не принадлежат второму множеству. [3,4,5,6..9] - [3,4,5,6] получится [7,8,9] ['K','L','M','N'] - ['K','L','N'] получится ['M'] 3) Пересечение - при пересечении двух множеств будет образовываться множество, состоящее из элементов, которые присутствуют в вступивших в реакцию множествах. [1,2,3,4,5..9] * [3,7,8,10,11,12] получится [3,7,8] Понятно, что в программах требуется делать не только такие операции, как пересечение, объединение, разность, но и требуется сравнивать их, делать выводы и по результатам этих выводов совершать определенные действия. Для этого существуют операторы сравнения, такие как "=", "<>", "<=", ">=". Разберемся с каждым по отдельности: 1) Оператор = - сравнивает два множества, если все элементы одного множества соответственно равны всем элементам другого множества, то такие множества равны и операция будет возвращать "правду" (True). [1,2,3,4..7] = [1,2,3,4,5,6,7] будет возвращать True. [1,2,3] = [5,6,7] будет возвращать False. 2) Оператор <> - противоположен оператору "=", то есть, если все элементы одного множества не равны элементам другого множества, то такие множества не равны и операция возвращает "истину" (True). [6,7,8,9] <> [10,11,12] будет возвращать True. 3) Оператор >= - сравнивает два множества, если элементы второго множества являются подмножеством первого оперируемого множества, то функция возвращает "истину" (True). Если говорить проще, то функция возвращает "правда", если первое множество содержит элементы второго. ['A'..'E'] >= ['B'..'D'] возвращает True. 4) Оператор <= - противоположен оператору ">=", то есть, если все элементы первого множества являются элементами второго множества, то тогда функция возвращает "истину" (True). [2,3,4,5..20] <= [1..100] возвращает True. Также есть и еще один оператор, а именно In, использующийся для проверки присутствия элемента к заданному множеству. Он очень часто используется, как и операторы сравнения, в операторах IF, Case. Синтаксис In представляет собой следующее: <элемент для проверки> in <множество для проверки>; Выражение такого типа будет возвращать "истину" (True), если элемент действительно присутствует во множестве, в обратном случает выражение возвращает "ложь" (False). ЗаключениеНужно было бы, говоря о структурированных классах, рассказать о файлах, способах работы с ними. Но так как эта тема очень объемна, то про нее надо писать отдельную статью. С первоначальными знаниями, полученными в этой статье, вы уже можете не бояться работать с большим количеством информации, но для больших и серьезных проектов этого недостаточно. Так что очень рекомендую читать специализированную литературу, искать информацию в Интернете и других источниках. Источник: "Компьютер Price", http://www.comprice.ru
| |||||
Copyright © "Internet Zone", info@izcity.com Копирование и использование данных материалов разрешается только в случае указания на журнал "Internet Zone", как на источник получения информации. При этом во всех ссылках обязательно явное указание адреса вэб-сайта http://www.izcity.com/. При наличии у копируемого материала авторов и источника информации - их также нужно указывать, наряду со ссылкой на нас. Подробнее условия использования материалов смотрите здесь. |