Двумерные массивы в среде Delphi. Описание. Транспонирование матрицы без дополнительных массивов.



Двумерные массивы в среде Delphi. Перестановка строк. Вставка строки в матрицу.

Различные способы создания простейших графических образов в среде Delphi , вывод готовых фигур, рисунков. Примеры движения фигур по горизонтали, по вертикали, по окружности.

Компонент Image (Изображение) служит для отображения файлов рисунков, как компонент Memo служит для отображения текстовых файлов. При помощи компонента Image можно загружать и отображать битовые карты, пиктограммы и метафайлы Windows. Внутреннее функционирование компонента Image достаточно разумно, чтобы понять, какого рода изображение загружается и позаботиться обо всем, касающемся отображения содержаний, палитр и всего остального, связанного с отображением рисунков в Windows-программе. При помощи Delphi отображение рисунка так же просто, как и отображение текстового файла.

Выберите компонент Image из страницы палитры компонентов Additional (Дополнительные) и опустите его на вашу форму. Замените свойство Align компонента Image на alClient.

Как и в случае формы TextViewer, мы добавим процедуру Open к просмотрщику битовых карт. Добавьте к классу TPictureViewer объявление переменной Filename и объявление процедуры Open, чтобы этот класс выглядел, как в Листинге

18. Символьные и строковые величины. Процедуры и функции обработки строковых величин, +преобразование числовых и стоковых величин. Формирование массива слов из данного предложения.

Символьные и строковые величины

В Delphi 1.0 существовал лишь единственный строковый тип String, полностью эквивалентный одноименному типу в Turbo Pascal и Borland Pascal. Однако, этот тип имеет существенные ограничения, о которых я расскажу позднее. три фундаментальных строковых типа: ShortString, AnsiString, и WideString. Кроме того, тип String теперь стал логическим. Т.е., в зависимости от настройки соответствующего режима компилятора (режим больших строк), он приравнивается либо к типу ShortString (для совместимости со старыми программами), либо к типу AnsiString (по умолчанию). Управлять режимом, можно используя директиву компиляции {$LONGSTRINGS ON/OFF} (короткая форма {$H+/-}) или из окна настроек проекта – вкладка "Compiler" -> галочка "Huge strings". Если режим включен, то String приравнивается к AnsiString, иначе String приравнивается ShortString. Из этого правила есть исключение: если в определении типа String указан максимальный размер строки, например String[25], то, вне зависимости от режима компилятора, этот тип будет приравнен к ShortString соответствующего размера.

Поскольку, как вы узнаете в дальнейшем, типы ShortString и AnsiString имеют принципиальное отличие в реализации, то я вообще не рекомендую пользоваться логическим типом String без указания размера, если Вы, конечно, не пишете программ под Delphi 1. Если же Вы все-таки используете тип String, то я настоятельно рекомендую прямо в коде Вашего модуля указывать директиву компиляции, устанавливающую подразумеваемый Вами режим работы компилятора. Особенно если Вы используете особенности реализации соответствующего строкового типа. Если этого не сделать, то однажды, когда Ваш код попадет в руки другого программиста, не будет никакой гарантии того, что его компилятор будет настроен, так же как и Ваш.

Поскольку по умолчанию, после установки Delphi, режим больших строк включен, большинство молодых программистов даже и не подозревают, что String может представлять что-то отличное от AnsiString. Поэтому, дальше в этой статье, любое упоминание типа String без указания размера, подразумевает, что он равен типу AnsiString, если не будет явно указано иное. Т.е., считается что настройка компилятора соответствует настройке по умолчанию.

Сразу же упомяну о различии между типами AnsiString и WideString. Эти типы имеют практически одинаковую реализацию, и отличаются лишь тем, что WideString используется для представления строк в кодировке UNICODE использующей 16-ти битное представление каждого символа (WideChar). Эта кодировка используется в тех случаях когда необходима возможность одновременного присутствия в одной строке символов из двух и более языков (помимо английского). Например, строк содержащих одновременно символы английского, русского и европейских языков. За эту возможность приходится платить – размер памяти, занимаемый такими строками в два раза больше размера, занимаемого обычными строками. Использование WideString встречается не часто, поэтому, я буду в основном рассказывать о строках типа AnsiString. Но, поскольку они имеют одинаковую реализацию, почти все сказанное относительно AnsiString будет действительно и для WideString, естественно с учетом разницы в размере каждого символа.

Строковый тип AnsiString, обычно используется для представления строк в кодировке ANSI, или других (например OEM) в которых для кодирования одного символа используется один байт (8 бит). Такой способ кодирования называется single-byte character set, или SBCS. Но, очень многие не знают о существовании еще одного способа кодирования многоязычных строк (помимо UNICODE) используемого в системах Windows и Linux. Этот способ называется multibyte character sets, или MBCS. При этом способе, некоторые символы представляются одним байтом, а некоторые, двумя и более. В отличие от UNICODE, строки, закодированные таким способом, требуют меньше памяти для своего хранения, но требуют более сложной обработки. Так вот, строковый тип AnsiString может использоваться для хранения таких строк. Я не буду подробно останавливаться на этом способе кодирования, поскольку он применяется крайне редко. Лично я, ни разу не встречал программ использующих данный способ кодирования.

Знатоки Delphi вероятно мне сразу напомнят еще и о типах pChar (pWideChar) и array [...] of Char. Однако, я считаю, что это не совсем строковые типы, но я расскажу и о них, поскольку они очень часто используются в сочетании со строковыми типами.

Итак, приведу основные характеристики строковых типов:Тип  Максимальный размер строки Размер переменной   Объем памяти, требуемый для хранения строки

String[n] где 0 <= n <= 255          n символов     n+1 байт         n+1 байт

ShortString      255 символов 256 байт         256 байт

AnsiString        ~2^31 символов 4 байта 4 байта + (0 .. 2 Гбайт)

WideString      ~2^30 символов 4 байта 4 байта + (0 .. 2 Гбайт)

pChar не ограничено 4 байта 4 байта + размер строки +1

pWideChar      не ограничено 4 байта 4 байта + (размер строки+1)*2

array [0..n] of Char        n        n+1 байт         n+1 байт

array [0..n] of WideChar n        (n+1)*2 байт   (n+1)*2 байт

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

array [0..n] of Char

Формально, этот тип не являются строковыми. Однако, в Delphi, он несколько отличаются от остальных типов массивов. А именно, если массив символов имеет нижнюю границу индекса равной 0, то Delphi считает такой тип совместимым по присваиванию со строковыми константами. Например, если переменная a будет описана как a :array[0..20] of Char, то оператор a := 'abc' будет допустим. Причём, значения элементов начиная с a[3] и до a[20] будут установлены в #0.

Больше ничего необычного в этом типе нет. Хотя забыл, есть ещё – оператор @ (получение указателя) для переменной такого типа возвращает значение типа pChar. Это очень удобно, поскольку переменные этого типа очень часто используются как буфер при работе с функциями Windows API. Например:

var

a :array[0..20] of Char;

ShortString, и String[n]

ShortString является частным случаем String[n], а если быть более точным, он полностью эквивалентен String[255].

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

var s :String[4];

Оно означает, что для переменной s будет статически выделена область памяти размером 5 байт.

Теперь, я думаю, Вам станет ясно, почему для типа String[n] существует ограничение 0<=n<=255. Это весь набор значений, которые могут быть представлены в одном байте. На всякий случай, отмечу, что размерность переменной (n) определяет размер выделяемой под эту переменную памяти, и он не зависит от размера строки, которая там хранится. Т.е., если, например переменная описана как String[30], то даже если присвоить ей значение 'abcd', то размер этой переменной все равно останется 31 байт. Это иногда бывает очень удобно, например, при записи (чтении) таких переменных в файл (из файла).

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

function StringLength (s :ShortString) :Cardinal;

begin

Result := Ord(s[0]);

end;

Как видите, это код существенно компактнее, и быстрее чем соответствующий код для pChar. Именно поэтому, он и применялся в языке Pascal.

Однако ясно, что ограничения переменных этого типа – максимальный размер строки 255 символов, и всегда максимальный размер занимаемой переменной памяти, вне зависимости от реально помещенной в нее строки, заставили разработчиков Delphi вести новые строковые типы. Вот к ним мы сейчас и перейдем.

В Delphi есть модуль System, содержащий ряд процедур обработки данных действительных типов. Наиболее распространенные из них перечислены в табл. 1.6. Много полезных процедур содержится также в модулях SysUtils и Math.

 Функции действительных типов

Функция              

Abs (x)  

Абсолютная величина х

АгсТаn(х)             

Арктангенс х

Cos (х)  

Косинус х (х выражается в радианах, а не в градусах)

Ехр (х)  

Экспоненциальная функция от х

Frac(x)  

 Дробная часть х

Int (х)     

Целая часть х. Несмотря на название, возвращает действительное значение (с плавающей запятой), т.е. просто устанавливает нуль в дробной части

Ln (х)    

Натуральный логарифм от х

Pi           

Число Пи

Round (х)             

Ближайшее к х целое значение. Возвращает значение целого типа. Условие "ближайшее к х" не работает, если верхнее и нижнее значения оказываются равноудаленными (например, ес-ли дробная часть точно равна 0,5). В этих случаях Delphi перекладывает решение на опера-ционную систему. Обычно процессоры Intel решают эту задачу в соответствии с рекоменда-цией IEEE округлять в сторону ближайшего четного целого числа. Иногда такой подход на-зывают "банкирским округлением"

Sin(x)    

Синус х

Sqr(x)    

Квадрат х, т.е. X*X

Sqrt (х)  

Квадратный корень от х

Trunc (х)              

Целая часть х. В отличие от Int, возвращающей действительное значение, Trunc возвращает целое

 

 

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

В Delphi указатели процедурного типа на методы применяются для сопоставления событий с образцами текста программы. С точки зрения синтаксиса, единственное отличие процедурного типа для метода от обычного процедурного типа состоит в фразе of object, следующей за прототипом процедуры или функции в случае метода. Особым образом применяется в процедурных методах указательное значение Nil. Это единственное указательное значение, которое можно присвоить процедурной переменной. После присвоения такого значения процедурная переменная становится неопределенной. Состояние определенности можно проверить с помощью функции Assigned.

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

Физически процедурные типы в Delphi совпадают с указательными, однако они различаются синтаксически, поэтому нельзя обращаться к функции или процедуре через указатель. Тем не менее при обращении к процедурной переменной задействуется именно значение указательного типа. В C/C++ переменная может иметь тип указателя на функцию. В версиях языка С до введения стандарта ANSI для обращения к соответствующей функции приходилось явно адресовать указатель. В версиях С, со-ответствующих стандартам ANSI, возможны как явная, так и неявная адресации указателей. Delphi удобна для тех, кому близок стиль ANSI.

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

Вариантные значения

При рассмотрении типа Record мы ознакомились с вариантной частью записи, где в одном фрагменте памяти можно хранить информацию нескольких типов. Такой метод недостаточно нагляден. Много ли пользы от того, чтобы найти в памяти действительное значение с фиксированной запятой и интерпретировать его, как целое! Тип Variant (не имеющий ничего общего с вариантной частью записи) более "проворен" и полезен в управлении данными разных типов. Переменным типа Variant можно присваивать любые значения любых целых, действительных, строковых и булевых типов. Для совместимости с другими языками программирования предусмотрена также возможность присвоения этим переменным значений даты/времени и объектов OLE Automation. Кроме того, вариантные переменные могут содержать массивы переменной длины и размерности с элементами указанных типов.

Все целые, действительные, строковые, символьные и булевы типы совместимы с типом Variant в отношении операции присваивания. Вариантные переменные можно сочетать в выражениях с целыми, действительными, строковыми, символьными и булевыми; при этом все необходимые преобразования Delphi выполняет автоматически. Можно произвольно задавать для выражении тип Variant в форме Variant (X).

 

В Object Pascal определены два особых значения Variant. Значение Unassigned применяется для указания, что вариантной переменной пока не присвоено значение какого бы то ни было типа. Значение Null указывает на наличие в переменной данных неизвестного типа или потерю данных. Разницу между этими двумя значениями трудно уловить. Значение Unassigned присваивается вариантным переменным автоматически при их создании, независимо от того, локальная это переменная или глобальная, и является ли она частью другой, структурной, переменной, такой как запись или массив. Unassigned означает, что к данной вариантной переменной еще не обращались. Null же означает, что к вариантной переменной обращались, но не ввели в нее никакой информации. Таким образом, Null указывает, что значение вариантной переменной недействительно или отсутствует.

Вариантные переменные предоставляют широкие возможности формирования выражений с переменными разных типов. Однако за это приходится платить большим, по сравнению с жестко задаваемыми типами, расходом памяти. К тому же на выполнение операций с вариантными переменными требуется больше времени.

Интересна проблема использования вариантной переменной как массива. Элементы этого массива должны быть одного типа. На первый взгляд, это вполне естественное условие. Однако элементам массива можно присвоить и тип Variant! Тогда каждый элемент сможет содержать информацию разных типов, в том числе массив Variant. Как правило, вариантные массивы создаются с помощью процедуры VarArrayCreate.

Для передачи двоичной информации между контроллерами автоматизации OLE и серверами обычно применяются вариантные массивы с элементами varByte. Вариантные массивы типа varByte не могут подвергаться никаким преобразованиям. Нельзя также переформатировать содержащуюся в них двоичную информацию. Эффективный доступ к ним осуществляется с помощью процедур VarArrayLock и VarArrayUnlock.

Элементы вариантного массива не могут иметь тип varString. Для создания вариантных массивов со строковыми элементами следует выбрать тип varOleStr.

Процедуры обработки вариантных массивов

 Процедуры и функции обработки вариантных массивов

Процедура/функция     

Описание

VarArrayCreate  

Создает вариантный массив с заданными пределами и типом

VarArrayDimCount           

Возвращает число измерений данного вариантного массива

VarArrayHighBound         

Возвращает верхний предел измерения вариантного массива

 

VarArrayLock      

Фиксирует вариантный массив

VarArrayLowBound          

Возвращает нижний предел измерения вариантного массива

VarArrayOf          

Возвращает вариантный массив с указанными элементами

VarArrayRedim  

Изменяет верхний предел вариантного массива

VarArrayUnlock  

Отменяет фиксацию вариантного массива

VarAsType          

Преобразует вариантную переменную в указанный тип

VarCast

Преобразует вариантную переменную в указанный тип и записывает значение

VarClear              

Сбрасывает значение вариантной переменной

VarCopy              

Копирует одну вариантную переменную в другую

VarFromDateTime            

Возвращает вариантную переменную, содержащую переменную даты/времени

VarIsArray           

Возвращает True, если вариантная переменная является массивом

 

Определение понятия

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

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

a[0]        

a[1]        

a[2]        

a[3]        

a[4]        

…           

a[n

Вектор (линейный или одномерный массив) - это пример массива , в котором элементы нумеруются одним индексом.

В качестве номера (индекса) элемента массива, в общем случае, используется выражение порядкового типа (чаще всего - это целая константа или переменная целого типа: integer, word, byte или shortint)

При обращении к элементу массива индекс указывается в квадратных скобках. Например, a[10], mass[6].

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

a[i] - всех элементов;

a[2*i] - элементов, стоящих на четных местах;

a[2*i-1] - элементов, стоящих на нечетных местах

Описание массива

Определение переменной как массив без предварительного описания типа массиваvar a,b,c: array[1..10] of integer;

 var

s : array[0..5] of integer;

k : array[0..5] of integer;

Примечание

Описание массива требуется компилятору для выделения памяти под его элементы.

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

Здесь переменные s и k считаются разных типов. Для обеспечения совместимости необходимо применять описание переменных через предварительное описание типа.

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

Над массивами не определены операции отношения. Сравнивать два массива можно только поэлементно.

Предварительное описание типа массиваconst

n = 5;

type

mas = array[1..n] of integer;

var

a : mas;

Примечание

Доступ к элементам массива будет осуществляться так: a[1], a[2], a[3], a[4], a[5] (т. е. массив содержит пять элементов).

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

Задание массива типизированной константойconst

x : array[0..5] of integer = (1, 2, 3, 4, 5, 6);

 

 

Примечание

В данном примере не только выделяется память под массив, но и происходит заполнение ячеек данными.

Элементы массива можно изменять в ходе программы (как и все типизированные константы).

Заполнение массива данными

§ Для заполнения массива данными (и его вывода) чаще всего используется цикл с параметром for

§ Для заполнения массива случайными числами используется функция random и процедура randomize (инициализации генератора случайных чисел). Формат записи такой: random(B - A) + A, где A и B берутся из интервала [A,B)

Ввод массива с клавиатурыfor i := 1 to n do

begin

write('a[', i, '] = '); readln(a[i])

end;

На экране:

a[1] = 1

a[2] = 5

a[3] = 3

a[4] = 0

Заполнение массива случайными числами randomize;

for i := 1 to n do

a[i] := random(90)+10;

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

Вывод в столбецfor i := 1 to n do

 writeln(a[i]);

Вывод в одну строку через пробел-разделительfor i := 1 to n do

write(a[i], ' ');

Вывод в одну строку c заданием форматаfor i := 1 to n do

write(a[i]:4);

Постановка задачи. Получить сумму элементов массива, состоящего из 10 целочисленных элементов. Элементы массива вводятся с клавиатуры.program array2;

var

sum:integer;

i:byte;

a:array[0..9] of word;

begin

sum := 0;

for i := 0 to 9 do

begin

write('a[', i, '] = ');

readln(a[i]);

sum := sum + a[i]

end;

writeln('sum = ', sum)

end.

 


Дата добавления: 2018-05-12; просмотров: 1168; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!