High — Функция Delphi

Содержание
Рисунок 6. Окно среды Delphi для создания нового модуля Вы увидите, что среда Delphi создаст в редакторе кода новую страницу с текстом нового модуля Unit1 (рисунок 7): Рисунок 7. Текст нового модуля в редакторе кода Сохраните модуль под именем MathLib, выбрав в меню команду File / Save (рисунок 8): Рисунок 8. Окно сохранения модуля Заметьте, что основная программа Console изменилась: в списке подключаемых модулей появилось имя модуля MathLib (рисунок 9). После слова in среда Delphi автоматически помещает имя файла, в котором находится модуль. Для стандартных модулей, таких как SysUtils, это не нужно, поскольку их местонахождение хорошо известно. Рисунок 9. Текст программы Console в окне редактора Теперь перейдем к содержимому модуля. Давайте объявим в нем константу Pi и две функции: Power — вычисление степени числа, и Average — вычисление среднего арифметического двух чисел: Вот как могла бы выглядеть программа, использующая модуль Math: После компиляции и запуска программы вы увидите на экране три числа (рисунок 10): Рисунок 10. Результат работы программы Console Стандартные модули языка Delphi В состав среды Delphi входит великолепный набор модулей, возможности которых удовлетворят даже самого привередливого программиста. Все модули можно разбить на две группы: системные модули и модули визуальных компонентов. К системным модулям относятся System, SysUtils, ShareMem, Math. В них содержатся наиболее часто используемые в программах типы данных, константы, переменные, процедуры и функции. Модуль System — это сердце среды Delphi; содержащиеся в нем подпрограммы обеспечивают работу всех остальных модулей системы. Модуль System подсоединяется автоматически к каждой программе и его не надо указывать в операторе uses . Модули визуальных компонентов (VCL — Visual Component Library) используются для визуальной разработки полнофункциональных GUI-приложений — приложений с графическим пользовательским интерфейсом (Graphical User Interface). Эти модули в совокупности представляют собой высокоуровневую объектно-ориентированную библиотеку со всевозможными элементами пользовательского интерфейса: кнопками, надписями, меню, панелями и т.д. Кроме того, модули этой библиотеки содержат простые и эффективные средства доступа к базам данных. Данные модули подключаются автоматически при помещении компонентов на форму, поэтому вам об этом заботиться не надо. Их список слишком велик, поэтому мы его не приводим. Все основные модули среды Delphi, включая модули визуальных компонентов, поставляются вместе с их исходными текстами на языке Delphi. По мере роста вашего профессионального опыта мы рекомендуем чаще обращаться к этим исходным текстам. Во-первых, в них вы найдете ответы на многие вопросы о внутреннем устройстве среды Delphi, а во-вторых, они послужат образцовым примером профессионального подхода в решении широкого круга задач. И, в-третьих, что не менее важно, это поможет научиться красиво и правильно (в рамках устоявшегося стиля) оформлять тексты Ваших собственных программ так, чтобы их с легкостью читали и понимали другие программисты. Исходные тексты стандартных модулей среды Delphi находятся в каталоге Delphi/Source. Область действия идентификаторов При программировании необходимо соблюдать ряд правил, регламентирующих использование идентификаторов: каждый идентификатор должен быть описан перед тем, как он будет использован; областью действия идентификатора является блок, в котором он описан; все идентификаторы в блоке должны быть уникальными, т.е. не повторяться; один и тот же идентификатор может быть по-разному определен в каждом отдельном блоке, при этом блоки могут быть вложенными; если один и тот же идентификатор определен в нескольких вложенных блоках, то в пределах вложенного блока действует вложенное описание; все глобальные описания подключенного модуля видны программе (подключающему модулю), как если бы они были сделаны в точке подключения; если подключаются несколько модулей, в которых по-разному определен один и тот же идентификатор, то определение, сделанное в последнем подключенном модуле перекрывает все остальные; если один и тот же идентификатор определен и в подключенном модуле, и в программе (подключающем модуле), то первый игнорируется, а используется идентификатор, определенный в программе (подключающем модуле). Доступ к идентификатору подключенного модуля возможен с помощью уточненного имени. Уточненное имя формируется из имени модуля и записанного через точку идентификатора. Например, чтобы в предыдущем примере получить доступ к стандартному значению числа ?, нужно записать System.Pi. Строки Строковые значения Строка — это последовательность символов. При программировании строковые значения заключаются в апострофы, например: Так как апостроф является служебным символом, для его записи в строке как значащего символа применяются два апострофа, следующих непосредственно друг за другом: Для записи отсутствующих на клавиатуре символов используется символ # , за которым следует десятичный номер символа в кодовой таблице ASCII, например: Строка, которая не содержит символов, называется пустой: Теперь, когда известно, что представляют собой строковые значения, займемся строковыми переменными. Строковые переменные Строковая переменная объявляется с помощью зарезервированного слова string или с помощью идентификатора типа данных AnsiString, например: Строку можно считать бесконечной, хотя на самом деле ее длина ограничена 2 ГБ. В зависимости от присваиваемого значения строка увеличивается и сокращается динамически. Это удобство обеспечивается тем, что физически строковая переменная хранит не сами символы, а адрес символов строки в области динамически распределяемой памяти (о динамически распределяемой памяти мы расскажем ниже). При создании строки всегда инициализируются пустым значением (»). Управление динамической памятью при операциях со строками выполняется автоматически с помощью стандартных библиотек языка Delphi. Вы конечно же можете описывать строковые типы данных и использовать их при объявлении переменных и типизированных констант, например: Символы строки индексируются от 1 до N+1, где N — реальная длина строки. Символ с индексом N+1 всегда равен нулю (#0). Для получения длины следует использовать функцию Length , а для изменения длины — процедуру SetLength (см. ниже). Для того чтобы в программе обратиться к отдельному символу строки, нужно сразу за идентификатором строковой переменной или константы в квадратных скобках записать его номер. Например, FriendName[1] возвращает значение ‘A’, а FriendName[4] — ‘x’. Символы, получаемые в результате индексирования строки, принадлежат типу Char. Достоинство строки языка Delphi состоит в том, что она объединяет в себе свойства строки самого языка Delphi и строки языка C. Оперируя строкой, вы оперируете значением строки, а не адресом в оперативной памяти. В то же время строка не ограничена по длине и может передаваться вместо C-строки (как адрес первого символа строки) в параметрах процедур и функций. Чтобы компилятор позволил это сделать, нужно, записывая строку в качестве параметра, преобразовать ее к типу PChar (тип данных, используемый в языке Delphi для описания нуль-терминированных строк языка C). Такое приведение типа допустимо по той причине, что строка всегда завершается нулевым символом (#0), который хоть и не является ее частью, тем не менее всегда дописывается сразу за последним символом строки. В результате формат строки удовлетворяет формату C-строки. О работе с нуль-терминированными строками мы поговорим чуть позже. Строки в формате Unicode Для поддержки работы со строками формата Unicode в язык Delphi имеется строковый тип данных WideString. Работа со строками типа WideString почти не отличается от работы со строками типа AnsiString; существуют лишь два отличия. Первое отличие состоит в представлении символов. В строках типа WideString каждый символ кодируется не одним байтом, а двумя. Соответственно элементы строки WideString — это символы типа WideChar, тогда как элементы строки AnsiString — это символы типа AnsiChar. Второе отличие состоит в том, что происходит при присваивании строковых переменных. Об этом вы узнаете чуть позже, прочитав параграф «Представление строк в памяти». Короткие строки Короткая строка объявляется с помощью идентификатора типа ShortString или зарезервированного слова string , за которым следует заключенное в квадратные скобки значение максимально допустимой длины, например: Короткая строка может иметь длину от 1 до 255 символов. Предопределенный тип данных ShortString эквивалентен объявлению string [255]. Реальная длина строки может быть меньше или равна той, что указана при ее объявлении. Например, максимальная длина строки Friend в примере выше составляет 30 символов, а ее реальная длина — 9 символов. Реальную длину строки можно узнать с помощью встроенной функции Length . Например, значение Length(Friend) будет равно 9 (количество букв в слове Alexander). Все символы в строке типа ShortString пронумерованы от 0 до N, где N — максимальная длина, указанная при объявлении. Символ с номером 0 — это служебный байт, в нем содержится реальная длина короткой строки. Значащие символы нумеруются от 1. Очевидно, что в памяти строка занимает на 1 байт больше, чем ее максимальная длина. Поэтому значение SizeOf(Friend) будет равно 31. Обратиться к отдельному символу можно так же, как и к символу обычной строки. Например, выражения FriendName[1] и FriendName[9] возвращают соответственно символы ‘A’ и ‘r’. Значения FriendName[10] .. FriendName[30] будут случайными, так как при объявлении типизированной константы FriendName символы с номерами от 10 до 30 не были инициализированы. Символы, получаемые в результате индексирования короткой строки, принадлежат типу Char. Поскольку существует два типа строк: обычные (длинные) строки и короткие строки, возникает закономерный вопрос, можно ли их совмещать. Да, можно! Короткие и длинные строки могут одновременно использоваться в одном выражении, поскольку компилятор языка Delphi автоматически генерирует код, преобразующий их тип. Более того, можно выполнять явные преобразования строк с помощью конструкций вида ShortString(S) и AnsiString(S). Операции над строками Выражения, в которых операндами служат строковые данные, называются строковыми . Они состоят из строковых констант, переменных, имен функций и строковых операций. Над строковыми данными допустимы операции сцепления и отношения. Операция сцепления (+) применяется для сцепления нескольких строк в одну строку. Выражение Результат ‘Object’ + ‘ Pascal’ ‘Object Pascal’ Операции отношения (=, <>, >, =, ‘ABCDE’ True ‘Office’ = ‘Office’ True ‘USIS’ > ‘US’ True Если короткой строке присваивается значение, длина которого превышает максимально допустимую величину, то все лишние символы справа отбрасываются. Объявление строки Выражение Значение строки Name: string[6]; Name := ‘Mark Twain’; ‘Mark T’ Допускается смешение в одном выражении операндов строкового и символьного типа, например при сцеплении строки и символа. Строковые ресурсы В языке Delphi существует специальный вид строковых данных — строковые ресурсы. Строковые ресурсы очень похожи на строковые константы, но отличаются от них тем, что размещаются не в области данных программы, а в специальной области выполняемого файла, называемой ресурсами. Если данные всегда загружаются вместе с кодом программы и остаются в оперативной памяти вплоть до завершения программы, то ресурсы подгружаются в оперативную память лишь по мере надобности. В программе строковые ресурсы описываются как обычные строковые константы, с той лишь разницей что раздел их описания начинается не словом const , а словом resourcestring : Использование строковых ресурсов ничем не отличается от использования строковых констант: На роль строковых ресурсов отлично подходят сообщения об ошибках, которые занимают много места в памяти и остаются не нужны до тех пор, пока в программе не возникнет ошибка. Использование ресурсов упрощает перевод пользовательского интерфейса на другие языки, поскольку замена текстовых сообщений может производиться непосредственно в выполняемом файле, т.е. без перекомпиляции программы. Форматы кодирования символов Существуют различные форматы кодирования символов. Отдельный символ строки может быть представлен в памяти одним байтом (стандарт Ansi), двумя байтам (стандарт Unicode) и даже четырьмя байтами (стандарт UCS-4 — Unicode). Строка «Wirth» (фамилия автора языка Pascal — прародителя языка Delphi) будет представлена в указанных форматах следующим образом (рисунок 11): Рисунок 11. Форматы кодирования символов Существует также формат кодирования MBCS (Multibyte Character Set), согласно которому символы одной строки кодируются разным количеством байт (одним или двумя байтами в зависимости от алфавита). Например, буквы латинского алфавита кодируются одним байтом, а иероглифы японского алфавита — двумя. При этом латинские буквы и японские иероглифы могут встречаться в одной и той же строке. Стандартные процедуры и функции для работы со строками Так как обработка строк выполняется практически в каждой серьезной программе, стандартно подключаемый модуль System имеет набор процедур и функций, значительно облегчающих этот процесс. Все следующие процедуры и функции применимы и к коротким, и к длинным строкам. Concat (S1, S2, . , Sn): string — возвращает строку, полученную в результате сцепления строк S1, S2, . Sn. По своей работе функция Concat аналогична операции сцепления (+). Copy (S: string, Index, Count: Integer): string — выделяет из строки S подстроку длиной Count символов, начиная с позиции Index. Delete (var S: string, Index, Count: Integer) — удаляет Count символов из строки S, начиная с позиции Index. Insert (Source: string; var S: string, Index: Integer) — вставляет строку Source в строку S, начиная с позиции Index. Length (S: string): Integer — возвращает реальную длину строки S в символах. SetLength (var S: string; NewLength: Integer) — устанавливает для строки S новую длину NewLength. Выражение Значение S S := Concat(‘Object ‘, ‘Pascal’);‘Object Pascal’S:= Copy(‘Debugger’, 3, 3);‘bug’S := ‘Compile’; Delete(S, 1, 3);‘pile’S := ‘Faction’; Insert(‘r’, S, 2)‘Fraction’ Pos (Substr, S: string): Byte — обнаруживает первое появление подстроки Substr в строке S. Возвращает номер той позиции, где находится первый символ подстроки Substr. Если в S подстроки Substr не найдено, результат равен 0. Выражение Результат Pos(‘rat’, ‘grated’)2Pos(‘sh’, ‘champagne’)0 Str (X [: Width [: Decimals] ], var S: string) — преобразует числовое значение величины X в строку S. Необязательные параметры Width и Decimals являются целочисленными выражениями. Значение Width задает ширину поля результирующей строки. Значение Decimals используется с вещественными числами и задает количество символов в дробной части. Выражение Значение S Str(-200, S);‘-200’Str(200 : 4, S);‘ 200’Str(1.5E+02 : 4, S);‘ 150’ Val (S: string, var V; var Code: Integer) — преобразует строку S в величину целого или вещественного типа и помещает результат в переменную V. Если во время операции преобразования ошибки не обнаружено, значение переменной Code равно нулю; если ошибка обнаружена (строка содержит недопустимые символы), Code содержит номер позиции первого ошибочного символа, а значение V не определено. Выражение Значение V Значение Code Val(‘100’, V, Code); 100 0 Val(‘2.5E+01’, V, Code); 25.0 0 Val(‘2.5A+01’, V, Code); 4 Описанные процедуры и функции являются базовыми для всех остальных подпрограмм обработки строк из модуля SysUtils. AdjustLineBreaks (const S: string): string — возвращает копию строки S, в которой все мягкие переносы строк (одиночные символы #13 или #10) заменены жесткими переносами строк (последовательность символов #13#10). AnsiCompareStr (const S1, S2: string): Integer — сравнивает две строки, делая различие между заглавными и строчными буквами; учитывает местный язык. Возвращаемое значение меньше нуля, если S1 S2. AnsiCompareText (const S1, S2: string): Integer — сравнивает две строки, не делая различий между заглавными и строчными буквами; учитывает местный язык. Возвращаемое значение меньше нуля, если S1 S2. AnsiDequotedStr (const S: string; Quote: Char): string — удаляет специальный символ, заданный параметром Quote, из начала и конца строки и заменяет парные спецсимволы на одиночные; если специальный символ отсутствует в начале или конце строки, то функция возвращает исходную строку без изменений. AnsiExtractQuotedStr (var Src: PChar; Quote: Char): string — делает то же, что и функция AnsiDequotedStr, но результат возвращается вместо исходной строки, которая имеет тип PChar. AnsiLowerCase (const S: string): string — преобразует заглавные буквы строки S к строчным буквам с учетом местного языка. AnsiPos (const Substr, S: string): Integer — выполняет те же действия, что и функция Pos, но в отличие от нее поддерживает работу с многобайтовой MBCS-кодировкой. AnsiQuotedStr (const S: string; Quote: Char): string — преобразует строку, заменяя все вхождения специального символа, заданного параметром Quote, на парные спецсимволы, а также помещает специальный символ в начало и конец строки. Поддерживает работу с MBCS-кодировкой. AnsiSameCaption (const Text1, Text2: string): Boolean — сравнивает две строки, не делая различие между заглавными и строчными буквами, а также не учитывая символ ‘&’; учитывает местный язык. AnsiSameStr (const S1, S2: string): Boolean — сравнивает строки, делая различие между строчными и заглавными буквами; учитывает местный язык. AnsiSameText (const S1, S2: string): Boolean — сравнивает строки, не делая различие между строчными и заглавными буквами; учитывает местный язык. AnsiUpperCase (const S: string): string — преобразует все строчные буквы в заглавные; учитывает местный язык. CompareStr (const S1, S2: string): Integer — выполняет сравнение двух строк, делая различие между строчными и заглавными буквами; не учитывает местный язык. Возвращаемое значение меньше нуля, если S1 S2. CompareText (const S1, S2: string): Integer — выполняет сравнение двух строк, не делая различий между строчными и заглавными буквами; не учитывает местный язык. Возвращаемое значение меньше нуля, если S1 S2. DateTimeToStr (const DateTime: TDateTime): string — преобразует значение даты и времени в строку. DateTimeToString (var Result: string; const Format: string; DateTime: TDateTime) — преобразует значение даты и времени в строку, выполняя при этом форматирование в соответствии со значением строки Format. Управляющие символы строки Format подробно описаны в справочнике по среде Delphi. DateToStr (const DateTime: TDateTime): string — преобразует числовое значение даты в строку. Format (const Format: string; const Args: array of const): string — форматирует строку в соответствии с шаблоном Format, заменяя управляющие символы шаблона на значения элементов открытого массива Args. Управляющие символы подробно описаны в справочнике по среде Delphi. FormatDateTime (const Format: string; DateTime: TDateTime): string — преобразует значение даты и времени в строку, выполняя при этом форматирование в соответствии со значением строки Format. Управляющие символы строки Format подробно описаны в справочнике по среде Delphi. BoolToStr (B: Boolean; UseBoolStrs: Boolean = False): string — преобразует булевское значение в строку. Если параметр UseBoolStrs имеет значение False, то результатом работы функции является одно из значений ‘0’ или ‘-1’. Если же параметр UseBoolStrs имеет значение True, то результатом работы является одно из значений ‘FALSE’ или ‘TRUE’ (программист может задать другие значения; о том, как это сделать, читайте в справочнике по системе Delphi). IntToHex (Value: Integer; Digits: Integer): string — возвращает шестнадцатиричное представление целого числа Value. Параметр Digits задает количество цифр результирующей строки. IntToStr (Value: Integer): string — преобразует целое число Value в строку. IsDelimiter (const Delimiters, S: string; Index: Integer): Boolean — проверяет, является ли символ S[Index] одним из символов строки Delimiters. Функция поддерживает работу с многобайтовой MBCS-кодировкой. IsValidIdent (const Ident: string): Boolean — возвращает True, если строка Ident является правильным идентификатором языка Delphi. LastDelimiter (const Delimiters, S: string): Integer — возвращает индекс последнего вхождения одного из символов строки Delimiters в строку S. LowerCase (const S: string): string — преобразует все заглавные буквы строки S к строчным; не учитывает местный язык (в преобразовании участвуют лишь символы в диапазоне от ‘A’ до ‘Z’). QuotedStr (const S: string): string — преобразует исходную строку в строку, взятую в одиночные кавычки; внутри строки символы кавычки дублируются. SameText (const S1, S2: string): Boolean — сравнивает строки, не делая различие между строчными и заглавными буквами; учитывает местный язык. SetString (var S: string; Buffer: PChar; Len: Integer) — копирует строку с типом PChar в строку с типом string. Длина копируемой строки задается параметром Len. StringOfChar (Ch: Char; Count: Integer): string — возвращает строку, в которой повторяется один и тот же символ. Количество повторений задается параметром Count. StringToGUID (const S: string): TGUID — преобразует строковое представление глобального уникального идентификатора в стандартный тип TGUID. StrToBool (const S: string): Boolean — преобразует строку в булевское значение. StrToBoolDef (const S: string; const Default: Boolean): Boolean — преобразует строку в булевское значение. В случае невозможности преобразования, функция возвращает значение, переданное через параметр Default. StrToDate (const S: string): TDateTime — преобразует строку со значением даты в числовой формат даты и времени. StrToDateDef (const S: string; const Default: TDateTime): TDateTime — преобразует строку со значением даты в числовой формат даты и времени. В случае невозможности преобразования, функция возвращает значение, переданное через параметр Default. StrToDateTime (const S: string): TDateTime — преобразует строку в числовое значение даты и времени. StrToDateTimeDef (const S: string; const Default: TDateTime): TDateTime — преобразует строку в числовое значение даты и времени. В случае невозможности преобразования, функция возвращает значение, переданное через параметр Default. StrToInt (const S: string): Integer — преобразует строку в целое число. Если строка не может быть преобразована в целое число, функция генерирует исключительную ситуацию класса EConvertError (обработка исключительных ситуаций рассматривается в главе 4). StrToIntDef (const S: string; Default: Integer): Integer — преобразует строку в целое число. Если строка не может быть преобразована в целое число, функция возвращает значение, заданное параметром Default. StrToInt64 (const S: string): Int64 — 64-битный аналог функции StrToInt — преобразует строку в 64-битное целое число. Если строка не может быть преобразована в 64-битное число, функция генерирует исключительную ситуацию класса EConvertError (обработка исключительных ситуаций рассматривается в главе 4). StrToInt64Def (const S: string; const Default: Int64): Int64 — 64-битный аналог функции StrToIntDef — преобразует строку в 64-битное целое число. Если строка не может быть преобразована в 64-битное число, функция возвращает значение, заданное параметром Default. StrToTime (const S: string): TDateTime — преобразует строку в числовой формат времени. Если строка не может быть преобразована в числовой формат времени, функция генерирует исключительную ситуацию класса EConvertError (обработка исключительных ситуаций рассматривается в главе 4). StrToTimeDef (const S: string; const Default: TDateTime): TDateTime — преобразует строку в числовой формат времени. В случае ошибки преобразования, функция возвращает значение, заданное параметром Default. TimeToStr (Time: TDateTime): string — преобразует числовое значение времени в строку. Trim (const S: string): string — возвращает часть строки S без лидирующих и завершающих пробелов и управляющих символов. Trim (const S: WideString): WideString — Unicode-аналог функции Trim — возвращает часть строки S без лидирующих и завершающих пробелов и управляющих символов. TrimLeft (const S: string): string — возвращает часть строки S без лидирующих пробелов и управляющих символов. TrimLeft const S: WideString): WideString — Unicode-аналог функции TrimLeft — возвращает часть строки S без лидирующих пробелов и управляющих символов. TrimRight (const S: string): string — возвращает часть строки S без завершающих пробелов и управляющих символов. TrimRight (const S: WideString): WideString — Unicode-аналог функции TrimRight — возвращает часть строки S без завершающих пробелов и управляющих символов. UpperCase (const S: string): string — преобразует все строчные буквы строки S в заглавные; не учитывает местный язык (в преобразовании участвуют лишь символы в диапазоне от ‘a’ до ‘z’). WideFormat (const Format: WideString; const Args: array of const): WideString — Unicode-аналог функции Format, учитывающий символы местного языка, — форматирует строку в соответствии с шаблоном Format, заменяя управляющие символы в шаблоне на значения элементов открытого массива Args. Управляющие символы подробно описаны в справочнике по системе Delphi. WideFmtStr (var Result: WideString; const Format: WideString; const Args: array of const) — аналог функции WideFormat. Отличие в том, что WideFmtStr возвращает результат через параметр Result, а не как значение функции. WideLowerCase const S: WideString): WideString — Unicode-аналог функции LowerCase (учитывает местный язык) — преобразует все заглавные буквы строки S к строчным буквам. WideSameCaption (const Text1, Text2: WideString): Boolean — Unicode-аналог функции AnsiSameCaption — сравнивает две строки, не делая различие между строчными и заглавными буквами, а также не учитывая символ ‘&’; учитывает местный язык. WideSameStr (const S1, S2: WideString): Boolean — Unicode-аналог стандартной операции сравнения строк — сравнивает две строки, делая различие между строчными и заглавными буквами. WideSameText (const S1, S2: WideString): Boolean — Unicode-аналог функции SameText (учитывает местный язык) — сравнивает строки, не делая различие между строчными и заглавными буквами. WideUpperCase (const S: WideString): WideString — Unicode-аналог функции UpperCase (учитывает местный язык) — преобразует все строчные буквы строки S в заглавные. WrapText (const Line: string; MaxCol: Integer = 45): string — разбивает текст Line на строки, вставляя символы переноса строки. Максимальная длина отдельной строки задается параметром MaxCol. WrapText (const Line, BreakStr: string; const BreakChars: TSysCharSet; MaxCol: Integer): string — более мощный аналог предыдущей функции — разбивает текст Line на строки, вставляя символы переноса строки. AnsiToUtf8 (const S: string): UTF8String — перекодирует строку в формат UTF8. PUCS4Chars (const S: UCS4String): PUCS4Char — возвращает указатель на первый символ строки формата UCS-4 для работы со строкой, как с последовательностью символов, заканчивающейся символом с кодом нуль. StringToWideChar (const Source: string; Dest: PWideChar; DestSize: Integer): PWideChar — преобразует стандартную строку к последовательности Unicode-символов, завершающейся символом с кодом нуль. UCS4StringToWideString (const S: UCS4String): WideString — преобразует строку формата UCS-4 к строке формата Unicode. Utf8Decode (const S: UTF8String): WideString — преобразует строку формата UTF-8 к строке формата Unicode. Utf8Encode (const WS: WideString): UTF8String — преобразует строку формата Unicode к строке формата UTF-8. Utf8ToAnsi (const S: UTF8String): string — преобразует строку формата UTF-8 к стандратной строке. WideCharLenToString (Source: PWideChar; SourceLen: Integer): string — преобразует строку формата Unicode к стандартной строке. Длина исходной строки задается параметром SourceLen. WideCharLenToStrVar (Source: PWideChar; SourceLen: Integer; var Dest: string) — аналог предыдущей функции — преобразует строку формата Unicode к стандартной строке. Длина исходной строки задается параметром SourceLen, а результат возвращается через параметр Dest. WideCharToString (Source: PWideChar): string — преобразует последовательность Unicode-символов, завершающуюся символом с кодом нуль, к стандартной строке. WideCharToStrVar (Source: PWideChar; var Dest: string) — аналог предыдущей функции — преобразует последовательность Unicode-символов, завершающуюся символом с кодом нуль, к стандартной строке. Результат возвращается через параметр Dest. WideStringToUCS4String (const S: WideString): UCS4String — преобразует строку формата Unicode к строке формата UCS-4. Массивы Объявление массива Массив — это составной тип данных, состоящий из фиксированного числа элементов одного и того же типа. Для описания массива предназначено словосочетание array of . После слова array в квадратных скобках записываются границы массива, а после слова of — тип элементов массива, например: После описания типа можно переходить к определению переменных и типизированных констант: Обратите внимание, что инициализация элементов массива происходит в круглых скобках через запятую. Массив может быть определен и без описания типа: Чтобы получить доступ к отдельному элементу массива, нужно в квадратных скобках указать его индекс, например Объявленные выше массивы являются одномерными, так как имеют только один индекс. Одномерные массивы обычно используются для представления линейной последовательности элементов. Если при описании массива задано два индекса, массив называется двумерным , если n индексов — n-мерным . Двумерные массивы используются для представления таблицы, а n-мерные — для представления пространств. Вот пример объявления таблицы, состоящей из 5 колонок и 20 строк: То же самое можно записать в более компактном виде: Чтобы получить доступ к отдельному элементу многомерного массива, нужно указать значение каждого индекса, например или в более компактной записи Эти два способа индексации эквивалентны. Работа с массивами Массивы в целом участвуют только в операциях присваивания. При этом все элементы одного массива копируются в другой. Например, если объявлены два массива A и B, то допустим следующий оператор: Оба массива-операнда в левой и правой части оператора присваивания должны быть не просто идентичны по структуре, а описаны с одним и тем же типом, иначе компилятор сообщит об ошибке. Именно поэтому все массивы рекомендуется описывать в секции type . С элементами массива можно работать, как с обычными переменными. В следующей программе элементы численного массива последовательно вводятся с клавиатуры, а затем суммируются. Результат выводится на экран. Для массивов определены две встроенные функции — Low и High. Они получают в качестве своего аргумента имя массива. Функция Low возвращает нижнюю, а High — верхнюю границу этого массива. Например, Low(A) вернет значение 1, а High(A) — 5. Функции Low и High чаще всего используются для указания начального и конечного значений в операторе цикла for . Поэтому вычисление суммы элементов массива A лучше переписать так: В операциях с многомерными массивами циклы for вкладываются друг в друга. Например, для инициализации элементов таблицы, объявленной как требуются два вложенных цикла for и две целые переменные Col и Row для параметров этих циклов: Массивы в параметрах процедур и функций Массивы, как и другие типы данных, могут выступать в качестве параметров процедур и функций. Вот как может выглядеть функция, вычисляющая среднее значение в массиве действительных чисел: Функция Average принимает в качестве параметра массив известной размерности. Требование фиксированного размера для массива-параметра часто является чрезмерно сдерживающим фактором. Процедура для нахождения среднего значения должна быть способна работать с массивами произвольной длины. Для этой цели в язык Delphi введены открытые массивы-параметры. Такие массивы были заимствованы разработчиками языка Delphi из языка Modula-2. Открытый массив-параметр описывается с помощью словосочетания array of , при этом границы массива опускаются: Внутри подпрограммы Average нижняя граница открытого массива A равна нулю (Low(A) = 0), а вот значение верхней границы (High(A)) неизвестно и выясняется только на этапе выполнения программы. Существует только два способа использования открытых массивов: обращение к элементам массива и передача массива другой подпрограмме, принимающей открытый массив. Нельзя присваивать один открытый массив другому, потому что их размеры заранее неизвестны. Вот пример использования функции Average: Заметьте, что во втором операторе открытый массив конструируется в момент вызова функции Average. Конструктор открытого массива представляет собой заключенный в квадратные скобки список выражений. В выражениях могут использоваться константы, переменные и функции. Тип выражений должен быть совместим с типом элементов массива. Конструирование открытого массива равносильно созданию и инициализации временной переменной. И еще одно важное замечание по поводу открытых массивов. Некоторые библиотечные подпрограммы языка Delphi принимают параметры типа array of const — открытые массивы констант . Массив, передаваемый в качестве такого параметра, обязательно конструируется в момент вызова подпрограммы и может состоять из элементов различных типов (!). Физически он состоит из записей типа TVarRec , кодирующих тип и значение элементов массива (записи рассматриваются ниже). Открытый массив констант позволяет эмулировать подпрограммы с переменным количеством разнотипных параметров и используется, например, в функции Format для форматирования строки (см. выше). Уплотнение структурных данных в памяти С целью экономии памяти, занимаемой массивами и другими структурными данными, вы можете предварять описание типа зарезервированным словом packed , например: Ключевое слово packed указывает компилятору, что элементы структурного типа должны храниться плотно прижатыми друг к другу, даже если это замедляет к ним доступ. Если структурный тип данных описан без ключевого слова packed , компилятор выравнивает его элементы на 2- и 4-байтовых границах, чтобы ускорить к ним доступ. Заметим, что ключевое слово packed применимо к любому структурному типу данных, т.е. массиву, множеству, записи, файлу, классу, ссылке на класс. Множества Объявление множества Множество — это составной тип данных для представления набора некоторых элементов как единого целого. Область значений множества — набор всевозможных подмножеств, составленных из его элементов. Все элементы множества должны принадлежать однобайтовому порядковому типу. Этот тип называется базовым типом множества . Для описания множественного типа используется словосочетание set of , после которого записывается базовый тип множества: Теперь можно объявить переменную множественного типа: Можно объявить множество и без предварительного описания типа: В выражениях значения элементов множества указываются в квадратных скобках: [2, 3, 5, 7], [1..9], [‘A’, ‘B’, ‘C’]. Если множество не имеет элементов, оно называется пустым и обозначается как [ ]. Пример инициализации множеств: Количество элементов множества называется мощностью . Мощность множества в языке Delphi не может превышать 256. Операции над множествами При работе с множествами допускается использование операций отношения (=, <>, >=, in . Операции сравнения (=, <>). Два множества считаются равными, если они состоят из одних и тех же элементов. Порядок следования элементов в сравниваемых множествах значения не имеет. Два множества A и B считаются не равными, если они отличаются по мощности или по значению хотя бы одного элемента. Выражение Результат [1, 2] <> [1, 2, 3] True [1, 2] = [1, 2, 2] True [1, 2, 3] = [3, 2, 1] True [1, 2, 3] = [1..3] True Операции принадлежности (>=, = B равно True, если все элементы множества B содержатся в множестве A. Выражение A = [1, 2] True [1, 2] in . Используется для проверки принадлежности элемента указанному множеству. Обычно применяется в условных операторах. Выражение Результат 5 in [1..9] True 5 in [1..4, 6..9] False Операция in позволяет эффективно и наглядно выполнять сложные проверки условий, заменяя иногда десятки других операций. Например, оператор можно заменить более коротким: Операцию in иногда пытаются записать с отрицанием: X not in S. Такая запись является ошибочной, так как две операции следуют подряд. Правильная запись имеет вид: not (X in S). Объединение множеств (+) . Объединением двух множеств является третье множество, содержащее элементы обоих множеств. Выражение Результат [ ] + [1, 2] [1, 2] [1, 2] + [2, 3, 4] [1, 2, 3, 4] Пересечение множеств (*) . Пересечение двух множеств — это третье множество, которое содержит элементы, входящие одновременно в оба множества. Выражение Результат [ ] * [1, 2] [ ] [1, 2] * [2, 3, 4] [2] Разность множеств (-) . Разностью двух множеств является третье множество, которое содержит элементы первого множества, не входящие во второе множество. Выражение Результат [1, 2, 3] — [2, 3] [1] [1, 2, 3] — [ ] [1, 2, 3] В язык Delphi введены две стандартные процедуры Include и Exclude, которые предназначены для работы с множествами. Процедура Include (S, I) включает в множество S элемент I. Она дублирует операцию + (плюс) с той лишь разницей, что при каждом обращении включает только один элемент и делает это более эффективно. Процедура Exclude (S, I) исключает из множества S элемент I. Она дублирует операцию — (минус) с той лишь разницей, что при каждом обращении исключает только один элемент и делает это более эффективно. Выражение Результат S := [1, 3]; [1, 3] Include(S, 2); [1, 2, 3] Exclude(S, 3) [1, 2] Использование в программе множеств дает ряд преимуществ: значительно упрощаются сложные операторы if , улучшается наглядность программы и понимание алгоритма решения задачи, экономится время разработки программы. Поэтому множества широко используются в библиотеке компонентов среды Delphi. Записи Объявление записи Запись — это составной тип данных, состоящий из фиксированного числа элементов одного или нескольких типов. Описание типа записи начинается словом record и заканчивается словом end . Между ними заключен список элементов, называемых полями , с указанием идентификаторов полей и типа каждого поля: Идентификаторы полей должны быть уникальными только в пределах записи. Допускается вложение записей друг в друга, т.е. поле записи может быть в свою очередь тоже записью. Чтобы получить в программе реальную запись, нужно создать переменную соответствующего типа: Записи можно создавать и без предварительного описания типа, но это делается редко, так как мало отличается от описания полей в виде отдельных переменных. Доступ к содержимому записи осуществляется посредством идентификаторов переменной и поля, разделенных точкой. Такая комбинация называется составным именем . Например, чтобы получить доступ к полям записи Friend, нужно записать: Обращение к полям записи имеет несколько громоздкий вид, что особенно неудобно при использовании мнемонических идентификаторов длиной более 5 символов. Для решения этой проблемы в языке Delphi предназначен оператор with, который имеет формат: Однажды указав имя записи в операторе with, можно работать с именами ее полей как с обычными переменными, т.е. без указания идентификатора записи перед идентификатором поля: Допускается применение оператора присваивания и к записям в целом, если они имеют один и тот же тип. Например, После выполнения этого оператора значения полей записи Friend станут равными значениям соответствующих полей записи BestFriend. Записи с вариантами Строго фиксированная структура записи ограничивает возможность ее применения. Поэтому в языке Delphi имеется возможность задать для записи несколько вариантов структуры. Такие записи называются записями с вариантами . Они состоят из необязательной фиксированной и вариантной частей. Вариантная часть напоминает условный оператор case . Между словами case и of записывается особое поле записи — поле признака . Оно определяет, какой из вариантов в данный момент будет активизирован. Поле признака должно быть равно одному из расположенных следом значений. Каждому значению сопоставляется вариант записи. Он заключается в круглые скобки и отделяется от своего значения двоеточием. Пример описания записи с вариантами: Обратите внимание, что у вариантной части нет отдельного end , как этого можно было бы ожидать по аналогии с оператором case . Одно слово end завершает и вариантную часть, и всю запись. На этом мы пока закончим рассказ о записях, но хотим надеяться, что читатель уже догодался об их потенциальной пользе при организации данных с более сложной структурой. High — Функция Delphi От Delphi 4 к Delphi 5 Перечислимые типы. Перечислимые типы определяют упорядоченное множество идентификаторов, представляющих собой возможные значения переменных этого типа. Вводятся эти типы для того, чтобы сделать код более понятным. В частности, многие типы Delphi являются перечислимыми, что упрощает работу с ними, поскольку дает возможность работать не с абстрактными числами, а с осмысленными значениями. Величины не имеют приоритетное значение друг перед другом, и их порядок следует определять последовательностью, в которой идентификаторы указаны. Для того чтобы объявлять перечислимый тип, используйте следующий синтаксис: typeName = (val1. valn); где typeName имя перечислимого типа, val — идентификаторы. Например, следующее объявление: Suite = (Club, Diamond, Heart, Spade); определяет перечислимый тип, названный Иск, его возможные величины являются Клуб, Алмаз, Сердце и Лопата. К сожалению, в Object Pascal нельзя использовать кириллицу. Когда вы объявляете перечислимый тип, вы определяете, что каждое значение val является константой типа typeName . Если идентификаторы val используются для другой цели в пределах той же области, то происходят конфликты присваивания имен. Например, вы объявляете следующий перечислимый тип: TSound = (Click, Clack, Clock); К сожалению, выражение Click является также именем метода определенного для TControl библиотеки Delphi VCL . Так, если вы напишите в своем приложении следующий программный код: procedure TForm1.DBGrid1Enter(Sender: TObject); var Thing: TSound; Вы получите ошибку компиляции; компилятор интерпретирует Click в пределах области процедуры как ссылку на метод, щелчок по форме. Вы можете работать по-другому, квалифицируя идентификатор таким образом, что если TSound объявляется в MyUnit, вы должны использовать: Лучшим решением, тем не менее, является выбор имен с некоторым изменением, например: TSound = (tsClick, tsClack, tsClock); TMyColor = (mcRed, mcBlue, mcGreen, mcYellow, mcOrange); Answer = (ansYes, ansNo, ansMaybe); Т.е. вы сохраняете понятный смысл имени, но не вступаете в конфликт с системой. Вы можете использовать значения (val1. valn) при объявлении переменных, например: var MyCard: (Club, Diamond, Heart, Spade); Но если вы объявляете MyCard, вы не можете объявить другую переменную в пределах той же области, использующей эти постоянные идентификаторы. Так, например: var Card1: (Club, Diamond, Heart, Spade); var Card2: (Club, Diamond, Heart, Spade); генерирует ошибку компиляции. Но объявление var Card1, Card2: (Club, Diamond, Heart, Spade); ошибку компиляции не дает. Или можно объявить таким образом: type Suit = (Club, Diamond, Heart, Spade); Соответствие между значениями перечисляемого типа и порядковыми номерами этих значений устанавливается порядком перечисления: первое значение в списке получает порядковый номер 0, второе значение — порядковый номер 1 и т.д. Максимальное число констант перечислимого типа составляет 65536 значений, поэтому фактически перечислимый тип задает некоторое подмножество целого типа Word и может рассматриваться как компактное объявление сразу группы целочисленных констант со значениями 0, 1 и т.д. Пусть, например, в программе должна быть переменная Mode, в которой зафиксирован один из возможных режимов работы приложения: чтение данных, их редактирование, запись данных. Можно, конечно, определить переменной Mode тип Word и присваивать этой переменной в нужные моменты времени одно из трех условных чисел: 0 — режим чтения, 1 — режим редактирования, 2 — режим записи. Тогда программа будет содержать операторы вида if (Mode = 1) then . Через некоторое время уже забудется, что означает значение Mode, равное 1, и разбираться в таком коде будет очень сложно. А можно поступить иначе: определить переменную Mode как переменную перечислимого типа и обозначить ее возможные значения как mRead, mEdit, mWrite . Тогда приведенный выше оператор изменится следующим образом: if (Mode = mEdit) then . Конечно, такой оператор понятнее, чем предыдущий. Переменная перечислимого типа может определяться предложением вида: var Mode : (mRead, mEdit, mWrite); Если переменная определена так, то ей можно присваивать указанные значения, можно проверять ее величину, сравнивая с возможными значениями. Кроме того, надо учитывать, что перечислимые типы относятся к целым порядковым типам и к ним применимы любые операции сравнения (>, = ( , . ); Тогда можно ввести в программе несколько переменных этого типа. Например: type TMode : (mRead, mEdit, mWrite); var Mode1, Mode2 : TMode; Для работы с перечислимыми типами имеется несколько системных подпрограмм, описанных в системном модуле Delphi. Подпрограмма Ord возвращает число, которое указывает на порядковый номер значения параметра среди значений типа данных. procedure TForm1.Button1Click(Sender: TObject); S := ‘Blue имеет порядковую величину ‘ + IntToStr(Ord(BLUE)) + #13#10; S := S + ‘Код ASCII для «c» — ‘ + IntToStr(Ord(‘c’)) + ‘ decimal’; MessageDlg(S, mtInformation, [mbOk], 0); На рисунке 1 представлен результат работы подпрограммы Ord. procedure Dec(var X[; N: Longint]); Процедура Dec уменьшает переданную в качестве параметра переменную на единицу или на значение необязательного второго параметра, т.е. уменьшает на единицу или на число N переменную. X — переменная перечислимого типа (включая Int64 ), или указатель, если позволен расширенный синтаксис. N — выражение целого типа. procedure TForm1.Button1Click(Sender: TObject); procedure Inc(var X [ ; N: Longint ] ); Процедура Inc увеличивает переданную в качестве параметра переменную на единицу или на заданное значение. X — переменная перечислимого типа (включая Int64 ), или указатель, если позволен расширенный синтаксис. N — выражение целого типа. Функция Odd возвращает True, если параметр нечетное число. function Odd(X: Longint): Boolean; procedure TForm1.Button1Click(Sender: TObject); Canvas.TextOut(10, 10, ‘5 нечетное.’) Canvas.TextOut(10, 10, ‘Четное!’); Функция Pred возвращает значение, которое в определяемой типом данных последовательности стоит перед значением параметра; предшественник. X — выражение порядкового типа (включая Int64). Результат того же самого типа как предшественник X. Succ возвращает значение, преемника. X — выражение порядкового типа (включая Int64). Результат того же самого типа как X — преемник X. Не используйте Succ в процедурах записи. Запишите следующий программный код, для проверки этой функции: procedure TForm1.Button1Click(Sender: TObject); S := ‘Предшественник для числа 5, ‘ + IntToStr(Pred(5)) + #13#10; S := S + ‘Преемник числа 10, ‘ + IntToStr(Succ(10)) + #13#10; if Succ(RED) = BLUE then S := S + ‘Красный цвет предшествненник синего.’; MessageDlg(S, mtInformation, [mbOk], 0); На рисунке 2 показано выдаваемое сообщение по результатам работы этой программы. Low возвращает самое низкое значение в диапазоне перечислимого типа, переданного как параметр. High возвращает самое высокое значение в диапазоне перечислимого типа данных. Рассмотрим пример, использующий функции Low и High. function Sum( var X: array of Double): Double; массива всегда нулевой.> for I := 0 to High(X) do S := S + X[I]; procedure TForm1.Button1Click(Sender: TObject); List1: array[0..3] of Double; List2: array[5..17] of Double; S, TempStr: string; for X := Low(List1) to High(List1) do for X := Low(List2) to High(List2) do List2[X] := X * 0.0123; S := ‘Sum of List1: ‘ + S + #13#10; S := S + ‘Sum of List2: ‘; MessageDlg(S, mtInformation, [mbOk], 0); Результат работы программы показан на рисунке 3. Ограниченные типы или тип-диапазон. Для порядковых типов можно задать диапазон их возможных значений для вводимого вами типа или переменной — это и будет ограниченный тип. Тип-диапазон задается границами своих значений внутри базового порядкового типа и описывается выражением вида: где определено минимальное и максимальное значение типа-диапазона. Например, если вы объявляете перечисленный тип type TColors = (Red, Blue, Green, Yellow, Orange, Purple, White, Black); type TMyColors = Green..White; Здесь TMyColors включает величины: зеленый, желтый, апельсиновый, пурпурный и белый. Вы можете использовать числовые константы и символы, чтобы определить ограниченный тип, например: Ограниченный тип не обязательно описывать в разделе type, его можно указывать непосредственно при объявлении переменной, например: В этих примерах переменная Alphabet может принимать только символы латинских букв в нижнем регистре, переменная Column принимает значения только целых чисел в диапазоне 1 — 12 (это могут быть, например, номера месяцев), переменная Day также принимает значения только целых чисел, но в диапазоне 1 — 31. При определении типа-диапазона необходимо руководствоваться следующими правилами: левое значение границы диапазона не должно превышать его правую границу; два символа > рассматриваются как один символ, поэтому между ними недопустимы пробелы. Тип-диапазон наследует все свойства своего базового типа, но с ограничениями, связанными с его меньшей емкостью. Так, по вполне понятным причинам процедуры Ord(X) и Pred(X) не всегда выполнимы. Рассмотрим пример с использованием процедуры Inc : type Percentile = 0..99; var I: Percentile; Для данного примера компилятор выдает ошибку, так как величина 100 не входит в диапазон объявленного ограниченного типа. Как вы помните, процедура Inc увеличивает переданную в качестве параметра переменную на единицу или на заданное значение. В стандартную библиотеку Object Pascal введены две функции, поддерживающие работу с типами-диапазонами: High(X) и Low(X). Ограниченные типы могут использоваться, например, для объявления размеров массивов, но и самостоятельно. В компиляторе Object Pascal имеется опция, позволяющая включить проверку диапазона при присваивании значения переменной ограниченного типа. Ее значение вы можете включить в том месте вашей программы, где вы хотите начать проверку диапазона, и выключить проверку, где захотите, опцией <$R->. Можно также включить опцию проверки в окне Project Options на странице Compiler . Это надежнее, так как опция работает только при возникновении ошибок диапазона, очевидных для компилятора, а установка опции проверки диапазона в окне Project Options действует в процессе выполнения (в режиме отладки) и при попытке присвоить переменной ограниченного типа значение, выходящее за пределы заданного диапазона, генерирует сообщение «Range check error «. Таким образом, введение ограниченных типов является неплохим средством отладки. Этот компонент предназначен для оформления вашего приложения. Bevel позволяет выделять группы элементов, отделять их друг от друга. type TBevelShape = (bsBox, bsFrame, bsTopLine, bsBottomLine, bsLeftLine, bsRightLine, bsSpacer); property Shape: TBevelShape; определяет контур компонента. type TBevelStyle = (bsLowered, bsRaised); property Style: TBevelStyle; определяет стиль компонента (вдавленный или выпуклый). На рисунке 4 показаны свойства компонента Bevel. ScrollBox представляет собой компонент-контейнер для размещения других компонентов. В нем имеется возможность прокрутки, в этом случае происходит экономия пространства формы при наличии большого количества управляющих элементов. Пользоваться этим компонентом достаточно просто. Поместите ScrollBox на форму и проведите размещение на управляющем элементе любых компонентов. Если очередной компонент выйдет за пределы рабочей области контейнера, то появятся полосы прокрутки (рисунок 5). property BorderStyle: TBorderStyle; определяет: если BorderStyle = bsNone, то компонент не имеет видимой границы обрамления; если BorderStyle = BsSingle, то компонент имеет видимую границу обрамления. Рассмотрим пример создания мультимедиа-приложения, в котором используем свойства компонента Bevel. Понятие мультимедиа применяется ко всему, что участвует в рождении качественного звука и изображения на компьютере, например мультимедиа-устройства и мультимедиа-программы. Используя свой компьютер, вы можете получать качественное воспроизведение звука на внешних HiFi-колонках или встроенных в монитор, а также видеть прекрасную картинку, просматривая фильм. Конечно, существует много мультимедийных приложений, созданных программистами. Но, наверно, очень интересно создать приложение самому, внешний вид которого можно изменить в любой момент, постоянно добавляя новые элементы для его улучшения. Музыкальные произведения, звуковые эффекты и записи речевой информации хранятся на носителях информации в файлах специальных форматов, среди которых чаще всего применяется формат WAV (от слова wave — волна). Для хранения видеоинформации чаще всего используются файлы с расширением AVI ( Audio-Video-Information ). Обычно аудио- и видео-файлы очень большие по объему, поэтому они размещаются на лазерных дисках. Наличие в вашем распоряжении видеокамеры позволит вам записывать видеоинформацию на компьютер, обрабатывать ее различными спецэффектами, и, может, из вас получится в будущем клипмейкер. Но даже если это вам не грозит, то обычная съемка с вашим оформлением принесет радость вашему окружению. Для создания мультимедиа-приложения используется компонент Delphi, имя которого MediaPlayer со страницы System палитры компонентов. Внешне компонент выглядит как панель управления магнитофона, видеомагнитофона или музыкального центра с девятью кнопками. Запустите Delphi. Используя свойство Caption, для компонента Form1 введите заголовок «CD-проигрыватель». Поместите на форму компонент Bevel. Установите в свойстве Style значение bsRaised. На компонент Bevel поместите Label, введите заголовок «Проигрыватель компакт-дисков». Выровняйте компоненты, чтобы Label1 был посередине Bevel1. Разместите на форме еще один компонент Bevel, оставьте без изменений установленное по умолчанию свойство Style равное bsLowered . Поместите на Bevel2 компонент MediaPlayer. Создайте мультимедиа приложение для проигрывания компакт-дисков. Для этого установите свойство Device Type в значение dtCDAudio, а свойству AutoOpen установите значение True. Используя комплексное свойство VisibleButtons, установите значения btStep = False, btBack = False, btRecord = False. Благодаря этим действиям с панели будут убраны все ненужные кнопки (рисунок 6) . После запуска приложения на компиляцию можете вставить компакт-диск в устройство CD-ROM и щелчком по кнопке Play осуществить воспроизведение ваших любимых мелодий. Можете добавить в свое приложение компонент Image и внедрить картинку. Размещение компонентов можно сделать как на рисунке 7, используя при этом всплывающее меню, вызываемое щелчком правой кнопкой мыши. Марко Канту. Delphi 2 для Windows 95/NT. Москва. ООО «Малип». 1997г. Джон Матчо. Дэвид Р. Фолкнер. Delphi. Москва. БИНОМ. 1995г. Эндрю Возневич. Delphi. Освой самостоятельно. Москва. Восточная книжная компания. 1996г. К. Сурков, Д. Сурков, А. Вальвачев. Программирование в среде Delphi 2.0. Минск. 1997 г. ООО «Попурри». В.В.Фаронов. Delphi 5. Учебный курс. Москва. Издательство Нолидж. 2000 г. А. Я. Архангельский. Программирование в Delphi 5. Москва. ЗАО «Издательство Бином». 2000г. Владимир Скуратов High — Функция Delphi Подпрограммы — процедуры и функции в языке Delphi служат для выполнения специализированных операций. Delphi имеет множество стандартных подпрограмм, но всё равно приходится создавать собственные для выполнения часто повторяющихся операций с данными, которые могут меняться. Вообще, существует методика программирования «сверху вниз». Методика программирования «сверху вниз» разбивает задачу на несколько более простых, которые оформляются в виде подпрограмм. Те, в свою очередь, при необходимости также делятся до тех пор, пока стоящие перед программистом проблемы не достигнут приемлемого уровня сложности (то есть простоты!). Таким образом, эта методика программирования облегчает написание программ за счёт создания так называемого скелета, состоящего из описателей подпрограмм, которые в дальнейшем наполняются конкретными алгоритмами. Пустое описание подпрограммы иначе называется «заглушкой». И процедуры, и функции позволяют добиться одинаковых результатов. Но разница всё же есть. Процедура Delphi просто выполняет требуемые операции, но никаких результатов своих действий не возвращает. Результат — в тех изменениях, которые произошли в программе в процессе выполнения этой процедуры. В частности, процедура может поменять значения переменных, записать новые значения в ячейки компонентов, сделать запись в файл и т.д. Функция Delphi также позволяет выполнить всё перечисленное, но дополнительно возвращает результат в присвоенном ей самой значении. То есть вызов функции может присутствовать в выражении справа от оператора присваивания. Таким образом, функция — более универсальный объект! Описание подпрограммы состоит из ключевого слова procedure или function, за которым следует имя подпрограммы со списком параметров, заключённых в скобки. В случае функции далее ставится двоеточие и указывается тип возвращаемого значения. Обычная точка с запятой далее — обязательна! Сам код подпрограммы заключается в «логические скобки» begin/end. Для функции необходимо в коде присвоить переменной с именем функции или специальной зарезервированной переменной Result (предпочтительно) возвращаемое функцией значение. Примеры: procedure Имя_процедуры(параметры); begin Код процедуры; end; function Имя_функции(параметры): тип_результата; begin Код функции; Result:= результат; end; Описанная таким образом подпрограмма должна быть размещена в основной программе до первого её вызова. Иначе при компиляции получите извещение о том, что «неизвестный идентификатор. » Следить за этим не всегда удобно. Есть выход — разместить только заголовок подпрограммы там, где размещают . Параметры — это список идентификаторов, разделённых запятой, за которым через двоеточие указывается тип. Если списков идентификаторов разных типов несколько, то они разделяются точкой с запятой. Всё, как и в случае обычного описания данных. Это так называемые формальные параметры. При вызове подпрограммы они заменяются на фактические — следующие через запятую данные того же типа, что и формальные. Параметры в описании подпрограммы могут и отсутствовать, тогда она оперирует данными прямо из основной программы. Теперь нужно ввести понятие локальных данных. Это данные — переменные, константы, подпрограммы, которые используются и существуют только в момент вызова данной подпрограммы. Они так же должны быть описаны в этой подпрограмме. Место их описания — между заголовком и началом логического блока — ключевым словом begin. Имена локальных данных могут совпадать с именами глобальных. В этом случае используется локальная переменная, причём её изменение не скажется на глобальной с тем же именем. Совершенно аналогично локальным типам, переменным, константам могут быть введены и локальные процедуры и функции, которые могут быть описаны и использованы только внутри данной подпрограммы. Теперь пример. Напишем программу суммирования двух чисел. Она будет состоять из Формы, на которой будет кнопка (компонент Button), по нажатию на которую будет выполняться наша подпрограмма, и двух строк ввода (компоненты Edit), куда будем вводить операнды. Начнём с процедуры. var Form1: TForm1; A, B, Summa: Integer; procedure Sum(A, B: Integer); procedure TForm1.Button1Click(Sender: TObject); begin A:=StrToInt(Edit1.Text); B:=StrToInt(Edit2.Text); Sum(A, B); Caption:=IntToStr(Summa); end; procedure Sum(A, B: Integer); begin Summa:=A+B; end; Наша процедура находится после обработчика нажатия кнопки, где осуществляется её вызов. И программа работает именно потому, что заголовок процедуры вынесен в блок описания данных. Но всё же операция суммирования в данном случае производится как-то невнятно. Теперь сделаем то же самое с помощью функции. var Form1: TForm1; A, B, Summa: Integer; function Sum(A, B: Integer): Integer; procedure TForm1.Button1Click(Sender: TObject); begin A:=StrToInt(Edit1.Text); B:=StrToInt(Edit2.Text); Summa:=Sum(A, B); // На мой взгляд, сейчас более понятно, откуда что берётся Caption:=IntToStr(Summa); end; function Sum(A, B: Integer): Integer; begin Result:=A+B; end; Есть особенности в использовании в качестве параметров больших по объёму структур данных, например, массивов, состоящих из нескольких тысяч (и больше) элементов. При передаче в подпрограмму данных большого объёма могут быть большие расходы ресурсов и времени системы. Поэтому используется передача не самих значений элементов (передача «по значению», как в предыдущих примерах), а ссылки на имя переменной или константы (передача «по имени»). Достигается это вставкой перед теми параметрами, которые мы хотим передать по имени, ключевого слова var. function Sum(A, B: Integer; var Arr: array[1..1000000] of Integer): Integer; Если взглянуть на описание нашей подпрограммы и описание обработчика нажатия кнопки (это тоже подпрограмма!), который был создан Delphi, то видим, что перед именем обработчика (Button1Click) стоит TForm1. Как мы знаем, в Delphi точкой разделяется объект и его атрибуты (свойства и методы). Таким образом, Delphi создаёт Button1Click как метод объекта Form1. Причём, буква T перед объектом говорит о том, что Button1Click не просто метод объекта, а метод класса объекта. Не будем этим пока заморачиваться, а просто будем поступать также. Описав свою процедуру или функцию как метод класса TForm1, мы получаем возможность использовать в ней объекты класса без указания его имени, что гораздо удобнее. То есть, если мы используем в нашей подпрограмме какие-либо компоненты, размещённые на Форме (например, Button1), то мы пишем Button1.W > а не Form1.Button1.W > Также появляется возможность использовать встроенные переменные, такие как параметр Sender. В каждом обработчике этот объект указывает на источник, то есть тот объект, который вызывает данную подпрограмму. Например, в нашей процедуре суммирования Sender = Button1. Проанализировав эту переменную, можно принять решение о тех или иных действиях. Описав подпрограмму как метод класса, её описание мы должны поместить туда же, куда их помещает описание класса TForm1. Смотрите сами, где находится описание процедуры Button1Click. Для этого, поставив курсор внутрь подпрограммы Button1Click, нажмите CTRL+Shift и кнопку управления курсором «Вверх» или «Вниз» одновременно. Произойдёт переход к описанию подпрограммы (чтобы вернуться обратно, повторите это действие ещё раз). Ставьте описание своей подпрограммы рядом, с новой строки. Обратите внимание, что TForm1 уже не пишется. Рекурсия — важное и мощное свойство процедур и функций в Delphi. Рекурсия это возможность подпрограммы в процессе работы обращаться к самой себе. Без использования рекурсии приходилось бы применять циклы, а это усложняет чтение программы. Рекурсивный вызов подпрограммы сразу проясняет смысл происходящего. Естественно, приходится следить за тем, чтобы в подпрограмме обязательно было условие, при выполнении которого дальнейшая рекурсия прекращается, иначе подпрограмма зациклится. Пример. Вычисление факториала Вычисление факториала — классическая в программировании задача на использование рекурсии. Факториал числа N — результат перемножения всех чисел от 1 до N (обозначается N!): Создавая программу вычисления факториала числа, мы можем применить и функции, и рекурсию. Можно скачать проект данной программы. Удобство применения рекурсии особенно наглядно при вычислении дискриминанта матрицы. Дискриминант матрицы можно подсчитать методом Гаусса — приведением матрицы к треугольному виду, что требует использования нескольких вложенных циклов. Алгоритм получается достаточно громоздкий. Используя вместо этого рекурсию, получается очень элегантный алгоритм: вычисление дискриминанта матрицы с использованием рекурсии. Функции Delphi модуля System Модуль System Предлагаем список функций модуля System, используемого в среде разработки Delphi. Abs Предназначена для получения абсолютной величины числа Addr Возвращает адрес переменной, функции или процедуры ArcTan Арктангенс числа, возвращается в радианах Assigned Осуществляет проверку функциональности указателей, объектов, методов BeginThread Начинает отдельный поток выполнения кода Chr Конвертирует целое число в символ Concat Соединяет несколько строк в одну Copy Создает копию части строки или части массива Cos Косинус числа Eof Возвращает true, если позиция курсора находится в конце файла открытого с помощью Reset Eoln Возвращает true, если позиция курсора находится в конце строки Exp Выдаёт экспоненту числа FilePos FileSetDate Установка даты и времени последнего изменения файла FileSize Выдает размер открытого файла в записях GetLastError Выдаёт код ошибки последнего неудачного Windows API вызова. GetMem Получает указанное число байтов памяти. Hi Возвращает байт старшего разряда от типа Integer. High Возвращает самое высокое значение типа или переменной Int Целая часть числа с плавающей точкой IOResult Содержит возвращаемый код последней операции ввода/вывода IsMultiThread Возвращает True, если код выполняет множество потоков Length Возвращает число элементов в массиве или строке Ln Выдает натуральный логарифм числа Lo Возвращает младший байт целого числа (2-байтового) Low Возвращает самое низкое значение типа или переменной Odd Провеяет, является ли целое число нечетным Ord Порядковое значение целого числа, символа или перечисления ParamCount Выдает число параметров переданной текущей программе ParamStr Возвращается один из параметров используемых для запуска текущей программы Pi Математическая константа Pos Находит позицию одной строки в другой Pred Уменьшает порядковую переменную Random Генерирует случайное целое число или число с плавающей запятой Round Округление чисел с плавающей запятой до целого числа RunError Заканчивает программу с диалогом ошибки SeekEof Пропускает символы, пока не встретится конец файла SeekEoln Пропускает символы, пока не встретится конец текущей строки или файла Sin Синус числа SizeOf Возвращает занимаемый размер типа или переменной в байтах Slice Создает часть массива с параметром «Открытый Массив» Sqr Возвращает квадрат числа Sqrt Возвращает квадратный корень числа StringOfChar Создает строку из одного символа, повторенного много раз StringReplace Заменяет одну или несколько подстрок, найденных в заданной строке StringToWideChar Преобразует обычную строку в WideChar-буфер с завершающим 0 Trunc Целая часть числа с плавающей запятой UpCase Преобразует значение Char к верхнему регистру WideCharToString Копирует строку WideChar, заканчивающуюся нулём, в нормальную строку Append Открывает текстовый файл, для добавления записей в файл (добавляет в конец файла) Assign Назначает дескриптор файла на бинарный или текстовый файл AssignFile Связывает дескриптор файла с бинарным или текстовым файлом BlockRead Читает блок записей данных из нетипизированного двоичного файла BlockWrite Записывает блок записей данных в нетипизированный двоичный файл Break Выполняет выход из одного цикла ChDir Выбор диска и директории ( папки ), в которой будет производиться работа Close Закрывает открытый файл CloseFile Закрывает открытый файл Continue Заставляет перейти к следующей итерации цикла Dec Декремент порядковой переменной Delete Удаляет часть символов из строки Dispose Очищает память на которую указывает указатель EndThread Заканчивает поток с кодом завершения Erase Стирает файл Exclude Исключает значение из переменной набора (множества) Exit Осуществляет выход из функции или процедуры Frac Дробная часть числа с плавающей запятой FillChar Заполняет раздел памяти значением байта или символа-заполнителя Flush Сбрасывает буферизованные данные текстового файла в файл GetDir Получает текущий каталог (диск плюс путь) для указанного диска. Halt Заканчивает программу с дополнительным диалогом. Inc Увеличивает порядковую переменную Include Включает значение во множество переменных Insert Вставляет строку в другую строку MkDir Создаёт каталог Move Копирует байты данных из источника в место назначения New Создаёт новую переменную типа указатель Randomize Устанавливает генератор случайного числа на следующее значение Read Позволяет прочитать данные из двоичного или текстового файла ReadLn Позволяет прочитать полную строку данных из текстового файла ReallocMem Позволяет изменить размер существующего блока памяти Reset Открывает текстовый файл для чтения, или двоичный файл для чтения/записи ReWrite Открывает текстовый или двоичный файл для записи RmDir Удаление каталога Seek Перемещает указатель в двоичном файле в новую позицию SetLength Изменяет размер строки или размер динамического массива SetString Копирует символы из буфера в строку Str Конвертирует целое число или число с плавающей точкой в строку Truncate Уменьшает размер файла — удаляя все данные после текущей позиции WriteLn Записывает законченную строку данных в текстовый файл
  • Программирование на языке Delphi. Глава 2. Основы языка Delphi. Часть 3
  • Оглавление
  • Программные модули
  • Структура модуля
  • Стандартные модули языка Delphi
  • Область действия идентификаторов
  • Строки
  • Строковые значения
  • Строковые переменные
  • Строки в формате Unicode
  • Короткие строки
  • Операции над строками
  • Выражение
  • Результат
  • Объявление строки
  • Выражение
  • Значение строки
  • Строковые ресурсы
  • Форматы кодирования символов
  • Стандартные процедуры и функции для работы со строками
  • Выражение
  • Значение S
  • Выражение
  • Результат
  • Выражение
  • Значение S
  • Выражение
  • Значение V
  • Значение Code
  • Массивы
  • Объявление массива
  • Работа с массивами
  • Массивы в параметрах процедур и функций
  • Уплотнение структурных данных в памяти
  • Множества
  • Объявление множества
  • Операции над множествами
  • Выражение
  • Результат
  • Выражение
  • Результат
  • Выражение
  • Результат
  • Выражение
  • Результат
  • Выражение
  • Результат
  • Выражение
  • Результат
  • Записи
  • Объявление записи
  • Записи с вариантами
  • High — Функция Delphi
  • High — Функция Delphi
  • Функции Delphi модуля System
  • Модуль System
  • Автокорреляционная функция

    13.05.2020, 02:42

    Автокорреляционная функция
    Добрый день! Есть сигнал first_step=0; step_t=0.01; last_step=1; N_=101;.

    Автокорреляционная функция
    Помогите создать программу на Паскале по этой теме: Сгенерировать случайную последовательность.

    Автокорреляционная функция С/А-кода
    Добрый день) Сформировала с/а-код и написала алгоритм который строит автокор. функцию, ставя в.

    Автокорреляционная функция дискретного сигнала
    Помогите, пожалуйста, понять как работает автокорреляционная функция дискретного сигнала. Я.

    Автокорреляционная функция синусоидального сигнала
    Подскажите пожалуйста почему не правильно строится автокорреляционная функция синусоидального.

    High — Функция Delphi

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

    О подпрограммах в Object Pascal

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

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

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

    write(‘Hello, world!’); readln;

    Здесь и write, и readln — стандартные подпрограммы Object Pascal. Таким образом, с вызовом подпрограмм мы уже знакомы. Осталось узнать, как создавать собственные, или пользовательские, подпрограммы. Но прежде отметим, что все подпрограммы делятся на 2 лагеря: процедуры и функции. Мы уже использовали эти термины, и даже давали им описание, однако повторимся: процедуры — это такие подпрограммы, которые выполняют предназначенное действие и возвращают выполнение в точку вызова. Функции в целом аналогичны процедурам, за тем исключением, что они еще и возвращают результат своего выполнения. Результатом работы функции могут быть данные любого типа, включая объекты.

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

    Как процедурам, так и функциям могут передаваться данные для обработки. Делается это при помощи списка параметров. Список параметров в описании подпрограммы и список аргументов, указываемых при ее вызове должен совпадать. Иначе говоря, если в описании определено 2 параметра типа Integer, то, вызывая такую подпрограмму, в качестве аргументов так же следует указать именно 2 аргумента и именно типа Integer или совместимого (скажем, Word или Int64).

    ПРИМЕЧАНИЕ
    На самом деле, Object Pascal позволяет довольно гибко обращаться с аргументами, для чего имеются различные методы, включая «перегружаемые» функции, значения параметров по умолчанию и т.д. Тем не менее, в типичном случае, количество, тип, и порядок перечисления аргументов при объявлении и при вызове процедуры или функции, должны совпадать.

    Любые подпрограммы выполняются до тех пор, пока не будет выполнена последняя инструкция в блоке подпрограммы, или пока в ее теле не встретится специальная процедура exit. Процедура exit досрочно прерывает выполнение подпрограммы и возвращает управление инструкции, следующей за вызовом данной подпрограммы.

    Процедуры

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

    Заголовок состоит из ключевого слова procedure, за которым следует имя процедуры и, при необходимости, список параметров, заключенных в круглые скобки:

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

    ПРИМЕЧАНИЕ
    Вопросы локальных и глобальных переменных, и вообще видимости в программах, будет рассмотрен позже в этой главе.

    После заголовочной части следует тело процедуры, заключаемое в begin и end. Таким образом, исходный код процедуры может выглядеть примерно таким образом:

    procedure TriplePrint(str: string); var i: integer; begin for i := 1 to 3 do begin writeln(‘»‘+str+'»‘); end; // конец цикла for end; // конец процедуры TriplePrint

    Здесь мы определили процедуру TriplePrint, которая будет трижды выводить переданную ей в качестве аргумента строку, заключенную в двойные кавычки. Как видно, данная процедура имеет все составные части: ключевое слово procedure, имя, список параметров (в данном случае он всего один — строковая переменная str), блок объявления собственных переменных (целочисленная переменная i), и собственное тело, состоящее из оператора цикла for.

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

    Отметим так же, что рассмотренная нами процедура сама содержит вызов другой процедуры — writeln. Процедуры могут быть встроенными. Иначе говоря, объявление одной процедуры можно помещать в заголовочную часть другой. Например, наша процедура TriplePrint может иметь вспомогательную процедуру, которая будет «подготавливать» строку к выводу. Для этого перед объявлением переменной i, разместим объявление еще одной процедуры. Назовем ее PrepareStr:

    procedure PrepareStr; begin str := ‘»‘+str+'»‘; end;

    Отметим, что переменная str, хотя и не передается этой процедуре в качестве параметра, тем не менее может в ней использоваться, поскольку данная процедура является составной частью процедуры TriplePrint, внутри которой данная переменная доступна для использования.

    Таким образом, мы получаем две процедуры, одна из которых (TriplePrint) может использоваться во всей программе, а другая (PrepareStr) — только внутри процедуры TriplePrint. Чтобы преимущество использования процедур было очевидно, рассмотрим их на примере программы, которая будет использовать ее неоднократно, для чего обратимся к листингу 6.1 (см. так же пример в Demo\Part1\Procs).

    Листинг 6.1. Использование процедур

    program procs; <$APPTYPE CONSOLE>procedure TriplePrint(str: string); procedure PrepareStr; begin str := ‘»‘+str+'»‘; end; var i: integer; begin PrepareStr; for i := 1 to 3 do begin writeln(str); end; end; // конец процедуры TriplePrint begin // начало тела основной программы TriplePrint(‘Hello. ‘); // первый вызов TriplePrint TriplePrint(‘How are you. ‘); // 2-й вызов TriplePrint(‘Bye. ‘); // 3-й readln; end.

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

    Функции

    Подобно процедурам, описание функции состоит из заголовка и тела. Однако описание заголовка имеет 2 отличия: прежде всего, для функций используется ключевое слово function. Кроме того, поскольку функции всегда возвращают результат, завершается строка заголовка типом возвращаемого значения. Таким образом, для объявления функции мы получаем следующий синтаксис:

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

    Рассмотрим пример функции, которая будет возвращать куб числа, переданного ей в качестве аргумента:

    function cube(value: integer) : integer; result := value * value * value; >

    Здесь определена функция, имеющая параметр value типа целого числа, которое она возводит в третью степень путем троекратного умножения, и результат присваивается специальной переменной result. Таким образом, чтобы в любом месте программы вычислить значение числа в 3-й степени, достаточно написать такое выражение:

    В результате выполнения этого выражения переменной x будет присвоено значение 27. Данный пример иллюстрирует использование функций в классическом случае — для явного вычисления значения переменной. Однако функции могут использоваться в выражениях и напрямую. Например, можно поставить вызов функции cube в каком-либо месте арифметического выражения подобно обычной переменной:

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

    procedure TriplePrint(str: string); function PrepareStr(s: string) : string; begin result := ‘»‘+s+'»‘; end; var i: integer; begin for i := 1 to 3 do begin writeln(PrepareStr(str)); // функция использована как переменная end; end;

    Как уже отмечалось, помимо специальной переменной result, в функциях можно использовать другую автоматически объявляемую переменную, имя которой соответствует имени функции. Так, для функции cube имя переменной также будет cube:

    function cube(value: integer) : integer; cube := value * value * value; >

    В данном случае оба варианта будут вести себя полностью аналогично. Различия проявляются лишь в том случае, если использовать такую переменную в выражениях в теле функции. В подобных случаях следует использовать именно переменную result, а не имя функции, поскольку использ0овании имени функции в выражении внутри самой функции приведет к ее рекурсивному вызову.

    Рекурсия

    Таким образом мы подошли к теме рекурсии — вызову подпрограммы из самой себя. Это не является ошибкой, более того, целый ряд алгоритмов решить без рекурсии вообще было бы затруднительно.

    Рассмотрим вопрос рекурсии на следующем примере:

    function recfunc(x: integer) : integer begin dec(x); // функция декремента, уменьшает целое на 1 if x > 5 then x := recfunc(x); result := 0; // возвращаемое значение тут не используется end;

    Здесь мы объявили функцию recfunc, принимающую один аргумент, и вызывающую саму себя до тех пор, пока значение этого аргумента больше 5. Хотя на первый взгляд может показаться, что такое поведение функции похоже на обычный цикл, на самом деле все работает несколько по-иному: если вы вызовите ее со значением 8, то она выдаст вам 3 сообщения в следующей последовательности: 5, 6, 7. Иначе говоря, функция вызывала саму себя до тех пор, пока значение x было больше 5, и собственно вывод сообщений начала 3-я по уровню получившейся вложенности функция, которая и вывела первое сообщение (в данном случае им стало 5, т.е. уменьшенное на единицу 6).

    Чтобы представить себе более наглядно, как работает рекурсивный вызов, дополним эту функцию выводом комментариев, а так же счетчиком глубины рекурсии. Для этого мы, во-первых, задействуем возвращаемое функцией значение, а во-вторых, добавим еще один параметр, который и будет счетчиком. Результат проделанной работы приведен в листинге 6.2.

    Листинг 6.2. Рекурсия с комментариями

    program recurse; <$APPTYPE CONSOLE>function recfunc(x, depth: integer) : integer; begin dec(x); if x > 5 then begin write(‘Current recursion depth is: ‘); write(depth); write(‘, current x value is: ‘); writeln(x); inc(depth); depth:=recfunc(x, depth); end else writeln(‘End of recursive calls. ‘); write(‘Current recursion depth is: ‘); write(depth); write(‘, current x value is: ‘); writeln(x); dec(depth); result := depth; end; begin recfunc(8,0); readln; end.

    Исходный код находится в Demo\Part1\Recurse, там же находится и исполняемый файл recurse.exe, результат работы которого вы можете увидеть на своем экране.

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

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

    procedure Circle (square: real; var radius, length: real);

    Данная процедура принимает «на обработку» одно значение — площадь (square), а возвращает через свои параметры два — радиус (radius) и длину окружности (length). Практическая ее реализация может выглядеть таким образом:

    procedure Circle (square: real; var radius, length: real); begin radius := sqrt(square / pi); // функция pi возвращает значение числа ? length := pi * radius * 2; end;

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

    var r,l: real; . Circle(100,r,l);

    После вызова функции Circle, переменные r и l получат значения радиуса и длины окружности. Остается их вывести при помощи writeln. Исходный код программы приведен в листинге 6.3.

    Листинг 6.3. Процедура с параметрами

    program params; <$APPTYPE CONSOLE>procedure Circle (square: real; var radius, length: real); begin //функция sqrt извлекает корень, а функция pi возвращает значение числа ? radius := sqrt(square / pi); length := pi * radius * 2; end; var r,l: real; begin Circle(100,r,l); writeln(r); writeln(l); readln; end.

    Запустив такую программу, можно убедиться, что она работает и выводит верные результаты, однако вид у них получается довольно-таки неудобочитаемый, например, длина окружности будет представлена как «3,54490770181103E+0001». Чтобы сделать вывод более удобным для восприятия, нам понадобится функция FloatToStrF. С ее помощью мы можем определить вывод числа на свое усмотрение, например:

    Кроме того, не помешало бы указать, где радиус, а где — длина окружности. Для этого модернизируем строки вывода результатов следующим образом:

    writeln(‘Radius is: ‘+FloatToStrF(r,ffFixed,12,8)); writeln(‘Length is: ‘+FloatToStrF(l,ffFixed,12,8));

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

    . var s,r,l: real; begin write(‘Input square: ‘); readln(s); Circle(s,r,l); writeln(‘Radius is: ‘+FloatToStrF(r,ffFixed,12,8)); writeln(‘Length is: ‘+FloatToStrF(l,ffFixed,12,8)); readln; end.

    В принципе, это уже лучше, однако не помешало бы добавить обработку возможных ошибок ввода. Скажем, площадь должна быть больше 0. Проверку на то, является ли значение s больше нуля, можно производить непосредственно в основном коде программы, но в целях создания более универсального кода, вынесем ее в подпрограмму. Для этого первой инструкцией процедуры Circle должна быть проверка значения площади:

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

    function Circle(square: real; var radius, length: real) : boolean; begin result := false; if (square

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

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

    if Circle(s,r,l) then begin // вывод end else // сообщить об ошибке

    Результатом проделанной работы будет программа, приведенная в листинге 6.4. Она же находится в Demo\Part1\Params.

    Листинг 6.4. Функция с параметрами

    program params; <$APPTYPE CONSOLE>uses sysutils; //этот модуль соджержит функцию FloatToStrF function Circle(square: real; var radius, length: real) : boolean; begin result := false; if (square

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

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

    function MyBetterFunc(val1: integer; const val2: integer = 2); begin result := val1*val2; end;

    Обращение же к такой функции может иметь 2 варианта: с указанием только одного аргумента (для параметра val1), или же с указанием обоих:

    x := MyBetterFunc(5); // получим 10 x := MyBetterFunc(5,4); // получим 20

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

    Области видимости

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

    program Project1; procedure Proc1; var a: integer; begin a := 5; //верно. Локальная переменная a здесь видна end; begin a := 10; //Ошибка! Объявленная в процедуре Proc1 переменнаая здесь не видна end.

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

    program Project2; var a: integer; // глобальная переменная a procedure Proc1; begin a := 5; // верно b := 10; // Ошибка! Переменая b на этот момент еще не объявлена end; var b: integer; // глобальная переменная b begin a := 10; // верно b := 5; // тоже верно. Здесь видны все г var a: integer; // глобальная переменная end.

    Теперь рассмотрим такой вариант, когда у нас имеются 2 переменных с одним и тем же именем. Разумеется, компилятор еще на стадии проверки синтаксиса не допустит, чтобы в программе были объявлены одноименные переменные в рамках одного диапазона видимости (скажем, 2 глобальных переменных X, или 2 локальных переменных X в одной и той же подпрограмме). Речь в данном случае идет о том, что произойдет, если в одной и той же программе будет 2 переменных X, одна — глобальная, а другая — локальная (в какой-либо подпрограмме). Если с основным блоком программы все ясно — в нем будет присутствовать только глобальная X, то как быть с подпрограммой? В таком случае в действие вступает правило близости, т.е. какая переменная ближе (по структуре) к данному модулю, та и есть верная. Применительно к подпрограмме ближней оказывается локальная переменная X, и именно она будет задействована внутри подпрограммы.

    program Project3; var X: integer; procedure Proc1; var X: integer; begin X := 5; // Здесь значение будет присвоено локальной переменной X end; begin X := 10; // Здесь же значение будет присвоено голобальной переменной X end.

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

    program Project1; procedure Proc1; procedure SubProc; begin end; begin SubProc; // Верно. Вложенная процедура здесь видна. end; begin Proc1; // Верно. Процедура Proc1 объявлена в зоне глобальной видимости SubProc; // Ошибка! Процедура SubProc недоступна за пределами Proc1. end.

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

    Видимость в модулях

    Все то, что мы уже рассмотрели, касалось программ, умещающихся в одном единственном файле. На практике же, особенно к тому моменту, когда мы перейдем к визуальному программированию, программы будут включать в себя множество файлов. В любом случае, программа на Object Pascal будет иметь уже изученный нами файл проекта — dpr, или основной модуль программы. Все прочие файлы будут располагаться в других файлах, или модулях (units), с типичным для Pascal расширением pas. При объединении модулей в единую программу возникает вопрос видимости переменных, а так же процедур и функций в различных модулях.

    Для начала вернемся к рассмотрению структуры модуля, которая имеет ряд отличий от структуры программы. Итак, в простейшем случае, модуль состоит из названия, определяемого при помощи ключевого слова unit, и 2 секций — interface и implementation. Так вот как раз первая секция, interface, и служит для определения (декларации) типов данных, переменных, функций и процедур данного модуля, которые должны быть доступны за пределами данного модуля.

    Чтобы лучше в этом разобраться, создадим программу, состоящую из 2 модулей — основного (dpr) и дополнительного (pas). Для этого сначала создайте новый проект типа Console Application, а затем добавьте к нему модуль, для чего из подменю File ‘ New выберите пункт Unit. После этого сохраните проект, щелкнув по кнопке Save All (или File ‘ Save All). Обратите внимание, что первым будет предложено сохранить не файл проекта, а как раз файл дополнительного модуля. Назовем его extunit.pas, а сам проект — miltiunits (см. Demo\Part1\Visibility). При этом вы увидите, что в части uses файла проекта произошло изменение: кроме постоянно добавляемого модуля SysUtils, появился еще один модуль — extunit, т.е. код стал таким:

    uses SysUtils, extunit in ‘extunit.pas’;

    Мы видим, что Delphi автоматически добавила пояснение, в каком файле находится подключаемый модуль. Это вызвано тем, что если о расположении собственных модулей Delphi все известно, то пользовательские модули могут находиться где угодно на жестком диске ПК. Но в данном случае мы сохранили и файл программы, и подключаемый модуль в одном каталоге, следовательно, их пути совпадают, и данное указание можно было бы опустить:

    uses SysUtils, extunit;

    Тем не менее, оставим код как есть, и приступим к разработке модуля extunit. В нем, в части implementation, напишем 2 процедуры — ExtProc1 и ExtProc2. Обе они будут делать одно и то же — выводить строку со своим названием. Например, для первой:

    Теперь вернемся к главному модулю программы и попробуем обратиться к процедуре ExtProc1:

    . begin ExtProc1; end.

    Попытка компиляции или запуска такой программы приведет к ошибке компилятора «Undeclared identifier», что означает «неизвестный идентификатор». И действительно, одного лишь описания процедуры недостаточно, чтобы она была доступна вне своего модуля. Так что перейдем к редактированию extunit и в секции interface напишем строку:

    Такая строка, помещенная в секцию interface, является объявлением процедуры ExtProc1, и делает ее видимой вне данного модуля. Отметим, что в секции interface допускается лишь объявлять процедуры, но не определять их (т.е. тело процедуры здесь будет неуместно). Еще одним полезным эффектом от объявления процедур является то, что таким образом можно обойти такое ограничение, как необходимость определения подпрограммы до ее вызова. Иначе говоря, поскольку в нашем файле уже есть 2 процедуры, ExtProc1и ExtProc2, причем они описаны именно в таком порядке — сначала ExtProc, а потом ExtProc2, то выведя объявление ExtProc2 в interface, мы сможем обращаться к ExtProc2 из ExtProc1, как это показано в листинге 6.5:

    Листинг 6.5. Объявление процедур в модуле

    unit extunit; interface procedure ExtProc1; procedure ExtProc2; implementation procedure ExtProc1; begin writeln(‘ExtProc1’); ExtProc2; // Если объявления не будет, то компилятор выдаст ошибку end; procedure ExtProc2; begin writeln(‘ExtProc2’); end; end.

    Отметим, что теперь процедуры ExtProc2, так же, как и ExtProc1, будет видна не только по всему модулю extunit, но и во всех использующей этот модуль программе multiunits.

    Разумеется, все, что было сказано о процедурах, верно и для функций. Кроме того, константы и переменные, объявленные в секции interface, так же будут видны как во всем теле модуля, так и вне него. Остается лишь рассмотреть вопрос пересечения имен, т.е. когда имя переменной (константы, процедуры, функции) в текущем модуле совпадает с таковым в подключенном модуле. В этом случае вновь вступает в силу правило «кто ближе, тот и прав», т.е. будет использоваться переменная из данного модуля. Например, если в extunit мы объявим типизированную константу Z, равную 100, а в multiunits — одноименную константу, равную 200, то обратившись к Z из модуля extunit, мы получим значение 100, а из multiunits — 200.

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

    Именно таким образом можно явно ссылаться на переменные, функции и процедуры, находящиеся в других модулях.

    Некоторые стандартные функции

    В Object Pascal, как уже отмечалось, имеются огромное количество стандартных процедур и функций, являющихся составной частью языка, и с некоторыми мы уже знакомы (например, приведенные в табл. 5.1 и 5.2 функции преобразования). Детальное описание всех имеющихся в Object Pascal процедур и функций можно получить в справочной системе Delphi, однако мы все-таки рассмотрим здесь некоторые из них, чтобы составить общее представление — см. таблицу 6.1.

    Таблица 6.1. Некоторые стандартные процедуры и функции Delphi

    Синтаксис Группа Модуль Описание
    function Abs(X); арифметические System Возвращает абсолютное значение числа
    procedure ChDir(const S: string); управления файлами System Изменяет текущий каталог
    function Concat(s1 [, s2. sn]: string): string; строковые System Объединяет 2 и более строк в 1
    function Copy(S; Index, Count: Integer): string; строковые System Возвращает часть строки
    function Cos(X: Extended): Extended; тригонометрические System Вычисляет косинус угла
    procedure Delete(var S: string; Index, Count: Integer); строковые System Удаляет часть строки
    function Eof(var F): Boolean; ввод-вывод System Проверяет, достигнут ли конец файла
    procedure Halt [ ( Exitcode: Integer) ]; управления System Инициирует досрочное прекращение программы
    function High(X); диапазона System Возвращает максимальное значение из диапазона
    procedure Insert(Source: string; var S: string; Index: Integer); строковые System Вставляет одну строку в другую
    function Length(S): Integer; строковые System Возвращает длину строки или количество элементов массива
    function Ln(X: Real): Real; арифметические System Возвращает натуральный логарифм числа (Ln(e) = 1)
    function Low(X); диапазона System Возвращает минимальное значение из диапазона
    procedure New(var P: Pointer); размещения памяти System Создает новую динамическую переменную и назначает указатель для нее
    function ParamCount: Integer; командной строки System Возвращает количество параметров командной строки
    function ParamStr(Index: Integer): string; командной строки System Возвращает указанный параметр из командной строки
    function Pos(Substr: string; S: string): Integer; строковые System Ищет вхождение указанной подстроки в строку и возвращает порядковый номер первого совпавшего символа
    procedure RmDir(const S: string); ввод-вывод System Удаляет указанный подкаталог (должен быть пустым)
    function Slice(var A: array; Count: Integer): array; разные System Возвращает часть массива
    function UpCase(Ch: Char): Char; символьные System Преобразует символ в верхний регистр
    function LowerCase(const S: string): string; строковые SysUtils Преобразует ASCII-строку в нижний регистр
    procedure Beep; разные SysUtils Инициирует системный сигнал
    function CreateDir(const Dir: string): Boolean; управления файлами SysUtils Создает новый подкаталог
    function CurrentYear: Word; даты и времени SysUtils Возвращает текущий год
    function DeleteFile(const FileName: string): Boolean; управления файлами SysUtils Удаляет файл с диска
    function ExtractFileExt(const FileName: string): string; имен файлов SysUtils Возвращает расширение файла
    function FileExists(const FileName: string): Boolean; управления файлами SysUtils Проверяет файл на наличие
    function IntToHex(Value: Integer; Digits: Integer): string; форматирования чисел SysUtils Возвращает целое в шестнадцатеричном представлении
    function StrPCopy(Dest: PChar; const Source: string): PChar; строковые SysUtils Копирует Pascal-строку в C-строку (PChar)
    function Trim(const S: string): string; строковые SysUtils Удаляет начальные и конечные пробелы в строке
    function TryStrToInt(const S: string; out Value: Integer): Boolean; преобразования типов SysUtils Преобразует строку в целое
    function ArcCos(const X: Extended): Extended; тригонометрические Math Вычисляет арккосинус угла
    function Log2(const X: Extended): Extended; арифметические Math Возвращает логарифм по основанию 2
    function Max(A,B: Integer): Integer; арифметические Math Возвращает большее из 2 чисел
    function Min(A,B: Integer): Integer; арифметические Math Возвращает меньшее из 2 чисел

    Те функции, которые имеются в модуле System, являются основными функциями языка, и для их использования не требуется подключать к программе какие-либо модули. Все остальные функции и процедуры можно назвать вспомогательными, и для их использования следует подключить тот или иной модуль, указав его в uses, например, как это делает Delphi уже при создании новой программы с SysUtils:

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

    Функции в действии

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

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

    1. Реализовать-таки возможность повторного прохождения игры без перезапуска программы;
    2. Добавить немного «геймплея». Иначе говоря, введем уровни сложности и подсчет очков. Новые уровни можно реализовать как повторное прохождение игры с увеличением сложности (скажем, за счет расширения диапазона загадываемых значений);
    3. В продолжение п. 2 добавить еще и таблицу рекордов, которая будет сохраняться на диске.

    Поскольку часть работы уже выполнена, то для того, чтобы приступить к разработке новой версии игры (назовем ее «Угадай-ка 2.0»), мы не будем как обычно создавать новый консольный проект в Delphi, а откроем уже существующий (Ugadaika) и сохраним его под новым именем, скажем, Ugadaika2, и в новом каталоге. Таким образом, мы уже имеем часть исходного кода, отвечающую за угадывание, в частности, цикл while (см. листинг 4.5). Этот фрагмент логичнее всего выделить в отдельную процедуру, вернее даже функцию, которая будет возвращать число попыток, сделанное пользователем. Для этого создадим функцию, которая будет принимать в качестве аргумента число, которое следует угадать, а возвращаемым значением будет целое, соответствующее числу попыток. Ее объявление будет таким:

    function GetAttempts(a: integer):integer;

    Данная функция так же должна иметь в своем распоряжении переменную, необходимую для ввода пользователем своего варианта ответа. Еще одна переменная нужна для подсчета результата, т.е. количества попыток. В качестве первой можно было бы использовать глобальную переменную (b), однако во избежание накладок, для локального использования в функции следует использовать локальную же переменную. Что касается переменной-счетчика, то для нее как нельзя лучше подходит автоматическая переменная result. Еще одним изменением будет использование цикла repeat вместо while. Это вызвано тем, что с одной стороны, тем, что хотя бы 1 раз пользователь должен ввести число, т.е. условие можно проверять в конце цикла, а с другой мы можем избавиться от присвоения лишнего действия, а именно — присвоения заведомо ложного значения переменной b. Ну и еще одно дополнение — это второе условие выхода, а именно — ограничение на число попыток, которое мы установим при помощи константы MAXATTEMPTS:

    const MAXATTEMPTS = 10;

    В результате код функции получится таким, как представлено в листинге 6.6.

    Листинг 6.6. Функция GetAttempts

    function GetAttempts(a: integer):integer; var b: integer; begin Result:=0; repeat inc(Result); // увеличиваем счетчик числа попыток write(#13+#10+’?:’); read(b); if (b>a) then begin write(‘Too much!’); continue; end; if (b

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

    var level, score, attempt: integer; f: TextFile; s: string;

    Теперь инициализируем счетчик псевдослучайных чисел (т.е. оставим randomize на месте) и инициализируем нулем значения счета и уровня:

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

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

    repeat writeln(‘Level ‘+IntToStr(level)+’:’); writeln(‘From 0 to ‘+IntToStr(level*100)); attempt:=GetAttempts(random(level*100+1)); score:=score+(MAXATTEMPTS-attempt)*level; writeln(#10+’You current score is: ‘+IntToStr(score)); inc(level); until attempt>MAXATTEMPTS;

    После завершения работы цикла, т.е. когда пользователь хоть раз истратит на отгадывание все 10 попыток, следует сообщить итоговый результат и сравнит его с предыдущим значением, которое следует считать из файла. Файл мы назовем records.txt, и сопоставим с переменной f:

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

    if not FileExists(‘record.txt’) then begin Rewrite(f); writeln(f,’0′); // первая строка содержит число-рекорд writeln(f,’None’); // а вторая — имя последнего победителя CloseFile(f); end;

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

    Reset(f); readln(f, attempt); readln(f,s); writeln(#10+’BEST SCORE: ‘+IntToStr(attempt)+’ by ‘+s); CloseFile(f);

    Ну и последнее, чего нам остается — это проверить, является ли новое значение выше рекорда, и если да — то записать новый рекорд в файл, не забыв спросить имя игрока:

    Вот, собственно, и все. Полный код получившейся программы можно увидеть на листинге 6.7, или же в файле проекта в каталоге Demo\Part1\Ugadaika2.

    Листинг 6.7. Программа угадай-ка, окончательный вариант

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

    Конспект

    Буду описывать здесь процесс выполнения различных работ.

    Страницы

    четверг, 1 марта 2012 г.

    Динамический массив в Delphi

    Как видим , мы просто говорим Delphi, что нам нужен одномерный массив типа Integer, а об его размере мы скажем когда нибудь потом.

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

    2. Для выделения памяти для динамического массива в Delphi используется процедура SetLength:

    После вызова этой процедуры будет выделена память для 20 элементов массива, которые будут проиндексированы от 0 до 19 (обратите внимание: индексирование начинается с нуля, а не с единицы!).
    После этого можно работать с динамическим массивом- присваивать ему значения, производить с элементами различные вычисления, вывод на печать и т.д.
    Например

    da_MyArray[0] := 5 ;
    da_MyArray[9] := 9 ;
    da_MyArray[1] := da_MyArray[0]+ da_MyArray[9] ;

    3. Как только динамический массив был распределен, вы можете передавать массив стандартным функциям Length, High, Low и SizeOf Функция Length возвращает число элементов в динамическом массиве, High возвращает самый высокий индекс массива (то есть Length — 1), Low возвращает 0. В случае с массивом нулевой длины наблюдается интересная ситуация: High возвращает -1, а Low — 0, получается, что High меньше Low. :) Функция SizeOf всегда возвращает 4 — длина в байтах памяти указателя на динамический массив

    iHigh := High (da_MyArray3);
    iLow := Low (da_MyArray3);

    4. Доступ к данным динамических массивов с помощью низкоуровневых процедур типа ReadFile или WriteFile , или любых других подпрограмм, получающих доступ сразу ко всему массиву, часто выполняется неправильно. Для обычного массива (его часто называют также статическим массивом — в противоположность динамическому массиву) переменная массива тождественна его данным. Для динамического массива это не так — переменная это указатель. Так что если вы хотите получить доступ к данным динамического массива — вы не должны использовать саму переменную массива, а использовать вместо неё первый элемент массива.

    правильно
    WriteFile(FHandle, da_MyArray02[0], Length(da_MyArray02), dwTemp, nil )

    неправильно
    WriteFile(FHandle, da_MyArray02, Length(da_MyArray02), dwTemp, nil )

    5. Рассмотрим пример присваивания динамических массивов одного другому

    После этих манипуляций da_A[0] равно 4. Дело в том , что при присвоении da_A:=da_B не происходит копирование т.к. da_A, da_B, это всего лишь указатели на область памяти. Для копирования необходимо использовать функцию Copy.

    6. Рассмотрим пример копирования динамических массивов с использованием функции Copy

    После этих манипуляций da_A[0] равно 3. После функции Copy da_A и da_B указывают на разные области памяти, поэтому при изменении da_B в da_A ничего не происходит и его значения остаются неизменными.

    7. Динамические массивы (например, array of Integer ) в Delphi в памяти расположены следующим образом. Библиотека runtime добавляет специальный код, который управляет доступом и присваиваниями. В участке памяти ниже адреса, на который указывает ссылка динамического массива, располагаются служебные данные массива: два поля — число выделенных элементов и счётчик ссылок (reference count).

    Расположение динамического массива в памяти

    Если, как на диаграмме выше, N — это адрес в переменной динамического массива, то счётчик ссылок массива лежит по адресу N — 8 , а число выделенных элементов (указатель длины) лежит по адресу N — 4 . Первый элемент массива (сами данные) лежит по адресу N .
    Для каждой добавляемой ссылки (т.е. при присваивании, передаче как параметр в подпрограмму и т.п.) увеличивается счётчик ссылок, а для каждой удаляемой ссылки (т.е. когда переменная выходит из области видимости или при переприсваивании или присваивании nil) счётчик уменьшается.

    8. Написал 2 программы, которые иллюстрируют теоретические сведения по динамическим массивам , приведенным в посте.

    Окно программы примера 1

    Окно программы примера 2

    Скачать программы- примеры с исходными кодами здесь : Dynamic-Array.rar

    Использовались функции SetLength, High, Low, Length, SizeOf, OpenFile, WriteFile, SetFilePointer, ReadFile, CloseHandle, ShellExecute, IntToStr, IntToHex, Integer, Copy, Ptr

    DelphiComponent.ru — бесплатно видеоуроки по Delphi, статьи, исходники

    Массивы в Delphi

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

    Мало того, что столь большое количество объявлений совершенно неприемлемо, такой подход порождает множество других проблем. Что делать, если требуется обновить состояние места в зависимости от информации, вводимой пользователем? Единственный способ решения этой задачи — использование огромного количества операторов if-then или case, которые должны были бы проверять введенное пользователем значение и изменять соответствующую переменную. Это означает, что для обеспечения простого изменения состояния только одного места пришлось бы написать, по меньшей мере, 350 строк кода:

    Очевидно, что должен существовать более рациональный способ работы с боль­шими коллекциями переменных. Лучший метод выполнения подобных задач свя­зан с использованием массива.

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

    Синтаксис объявления массива выглядит следующим образом:

    ИмяМассива: array[Диапазон] of ТипДанных; Cinema: array[1..350] of Boolean;

    Чтобы обратиться к переменной в массиве, необходимо указать имя массива, за которым должен следовать индекс переменной. Индекс переменной должен быть заключен в квадратные скобки. Синтаксис обращения к отдельному элементу мас­сива показан ниже:

    Так, например, если мы используем массив Cinema, и нам необходимо изме­нить состояние места номер 265 на свободное, можно записать следующую строку кода:

    Cinema[265] : = False; Индекс элемента не обязательно должен быть постоянным значением. Он мо­жет быть переменной, а также результатом выполнения функции. Важно помнить, что значение индекса должно лежать в пределах объявленного диапазона.

    Классификация типов данных в Delphi. Типы с плавающей точкой (Double, Single, Real, Extended)

    Типы бывают: 1)Простые/Порядковые (целый, логический, символьный, перечисляемый, диапазон (интервальный тип)); 2)Вещественный; 3)Структурированные(массивы, записи, файлы, классы, интерфейсы); 4)Строки; 5)Указатели; 6)Вариант; 7)Процедурный тип.

    Типы с плавающей точкой:

    Тип Размер(byte) Кол-во значащих цифр Диапазон
    Single 7-8 1.5e-45 … 3.4e38
    Double 15-16 5.0e-324 . 1.7e308
    Real 11-12 2.9e-39 … 1.7e38
    Extended 19-20 3.4e-4951 … 1.1e4932

    S-e-m

    Здесь m – знаковый разряд числа; e – экспоненциальная часть (содержит двоичный порядок); m – мантисса числа.

    Мантисса m имеет длину от 23 (для Single) до 63 (для Extended) двоичных разрядов, что и обеспечивает точность 7-8 для Single и 19-20 для Extended десятичных цифр. Десятичная точка(запятая) подразумевается перед левым (старшим) разрядом мантиссы, но при действиях с числом она сдвигается влево и вправо в соответствии с двоичным порядком числа, хранящимся в экспоненциальной части, поэтому действия над вещественными числами называют арифметикой с плавающей точкой(запятой).
    Особые операции :
    Round( r ) – 3 округление (r= 2.6);
    Trunc ( 2.8 ) – 2 целая часть;
    Int (2.8 ) – 2.0 округление дробной части;
    Frac (2.8) – 0.7 дробная часть.
    11. Порядковые типы. Целые типы в Delphi, тип диапазон

    К порядковым типам относятся целые типы, логический и символьный типы, а так же перечисления и тип-диапазон(пользовательский тип). К любому из них применима функция ORD(X) , которая возвращает порядковый номер значения выражения X. Для целых типов ORD(X) возвращает само значение X. Применение к логическому, символьному и к перечислениям дает «+» целое число в диапазоне 0-1(лог. тип), 0-255 (символьный), 0-65535 (перечисление). У типа-диапазон результат применения ord(x) зависит от свойств базового порядкового типа.
    Так же к порядковым типам можно применять функции:
    PRED(X) – возвращает предыдущее значение порядкового типа ( ord(pred(x)) = ord(x)-1).

    SUCC(X)– возвращает следующее значение порядкового типа( ord(succ(x)) = ord(x)+1).
    Вот некоторые целые типы :

    Название типа Размер в байтах Диапазон
    Byte 0…255
    Shortint -128…127
    Word 0…65535
    Integer -2147483647…2147483295

    К типам применимы следующие функции :

    Abs(x)–возвращает модуль X

    Chr(x)–возвращает символ по его коду

    Dec(x)–уменьшает значение на 1

    Inc(x)–увеличивает значение на 1
    Div–целочисленное деление

    Mod–дробная часть деления

    Sqr(x)–возвращает квадрат X

    А так же операции *,/,+,.
    При работе с данными, нужно следить за тем, чтобы они не выходили за границы диапазона значений.
    Тип-диапазон – это подмножество своего базового типа, в качестве которого может выступать любой порядковый тип, кроме типа-диапазона. Задается границами своих значений внутри базового типа : .. .Есть две функции : HIGH(x) — возвращает максимальное значение типа-диапазона, к которому принадлежит переменная Х.
    LOW(x) — возвращает минимальное значение типа-диапазона.

    12.Порядковые типы. Символьный тип. Таблица символов.
    Значениями символьного типа является множество символов компьютера. Каждому символу присваивается целое число в диапазоне от 0 до 255. Это число служит кодом внутреннего представления символа, его возвращает функция ORD. В Delphi 7 есть три символьных типа :

    Тип ANSIChar представляет собой так называемые Ansi-символы. Это символы, которые используются в операционных системах семейства Windows(размером 1 байт). Тип WideChar предназначен для хранения так называемых Unicode-символов, которые в отличие от Ansi-симвояов занимают два байта. Это позволяет кодировать символы числами от 0 до 65535 и используется для представления различных азиатских алфавитов. Первые 256 символов в стандарте Unicode совпадают с символами Аnsi.Тип Char в Delphi 7 эквивалентен типу AnsiChar и обеспечивает наибольшую производительность. Для отображения множества символов в подмножество натуральных чисел и обратно имеются следующие две стандартные функции:

    ord(c) — дает порядковый номер символа с;
    chr(i) — дает символ с порядковым номером i.
    UpCase(CH) – возвращает прописную букву, если CH– строчная латинская буква, в противном случае возвращает сам символ.
    Length( ) – функция, результатом которой является длина указанной строки.
    13.Логический тип. Логические операторы и операции сравнения.
    Значениями логического типа может быть одна из предварительно объявленных констант False или True.
    Ord (False) =0; Ord (True) = 1; False

    14.Порядковые типы. Перечисляемый тип.(пользовательский тип)
    Перечисление, или перечисляемый тип
    , задается перечислением тех значений, которые он может получать. Каждое значение именуется некоторым идентификатором и располагается в списке, обрамленном круглыми скобками, например :
    Type
    TSound = (‘ click, clack, clock’);

    Описание переменных : var snd:TSound;
    Особые операции:
    ord(snd) – возвращает номер значения по порядку начиная с нуля(нумерацию можно начинать с единицы, если в типе указать : Type TSound = (‘click’=1,’ clack, clock’).

    15.Тип массив(статический) : описание, ввод, вывод. Форматный вывод.
    Это пользовательский тип.
    Отличительная особенность массивов заключается в том, что все их компоненты – суть данные одного типа. Эти компоненты можно легко упорядочить и обеспечить доступ к любому из них простым указанием его порядкового номера.
    Описание типа массива : = array [ ] of ;
    – правильный идентификатор; array,of – зарезервированные слова(массив, из); – список из одного или нескольких индексных типов, разделенных запятыми; – любой тип Паскаля.
    В качестве индексных типов в Паскале можно использовать любые порядковые типы, кроме LongInt и типов-диапазонов с базовым типом LongInt.
    Обычно в качестве индексного типа используется тип-диапазон, в котором задаются границы индексов. Так как тип за словом of,– это любой тип Паскаля, он может быть, в частности, и другим массивом, например :
    type mat = array [0..5,-1..2,Char] of Byte.

    Ввод и вывод begin a.b : =100; writeln(a.b); End.

    16.Тип запись : описание, ввод, вывод, Оператор With. Запись с вариантами.
    Запись
    – это структура данных, состоящая из фиксированного количества компонентов, называемых полями записи. В отличие от массива компоненты (поля) записи могут быть различного типа. Чтобы можно было ссылаться на тот или иной компонент записи, поля именуются.
    Структура объявления типа записи такова :
    = record end;
    – правильный идентификатор ;record,end – зарезервированные слова(запись, конец); – список полей, представляющий собой последовательность разделов записи, между которыми ставится точка с запятой. Каждый раздел записи состоит из одного или нескольких идентификаторов полей, отделяемых друг от друга запятыми. За идентификатором(-ми) ставится двоеточие и описание типа поля(-ей).
    Описание : type BirthDay = record
    day, month : Byte;
    year : Word end;
    var a, b: BirthDay;

    К каждому из компонентов записи можно получить доступ, если использовать составное имя, то есть указать имя переменной, затем точку и имя поля : a. Day : = 27
    Для вложенных полей приходится продолжать уточнения :
    Type BirthDay = record …. End;
    var c : record
    name : String ;
    bd : BirthDay ;
    end;
    begin
    …. If c. bd. Year = 1939 then
    end.
    Чтобы упростить доступ к полям записи, используется оператор присоединения WITH :
    with do
    with, do – ключевые слова ( с, делать) ; – имя переменной типа запись, за которой, возможно, следует список вложенных полей; – любой оператор Паскаля.
    Например : with c. bd do month : = 9;
    В Паскале допускается использовать записи с так называемыми вариантными полями, например :
    Type Forma = record
    Name :String ;
    case Byteof
    0 : (BirthPlace : String [40] ) ;
    1 : ( Country : String [20] ) ;
    end;
    17.Тип множество : описание, ввод, вывод, операции над множествами.
    Множество
    – это наборы однотипных, логически связанных друг с другом объектов. Характер связей между объектами лишь подразумевается программистом и никак не контролируется в Паскалем. Количество элементов, входящих в множество, может меняться в пределах от 0 до 256. Именно непостоянством количества своих элементов множества отличаются от массивов и записей.
    Два множества эквивалентны ó все их элементы одинаковые, причем порядок следования может быть разным. Если одни элементы одного множества входят также и в другое, то говорят о включении первого множества во второе.
    Пример определения и задания множеств :
    type
    digitChat = set of ‘0’ .. ‘9’ ;
    var s1,s2,s3: digitChar;

    Ввод и вывод : S1:=[ 1..10]; … Writeln(s1); End.

    S2:=[‘2’,’3’,’1’];
    s3:=[‘2’,’3’];

    end.
    В этом примере s1 и s2 эквивалентны, а s3 включено в s2, но не эквивалентно ему.
    Описание :
    = set of
    – правильный идентификатор;set, of – зарезервированные слова (множество, из); – базовый тип элементов множества, в качестве которого может использоваться любой порядковый тип, кроме Word, Integer, LongInt.
    Над множествами определены следующие операции :
    а) пересечение множеств (*) – результат содержит элементы, общие для обоих множеств.
    б) объединение множеств (+) – результат содержит элементы первого множества, дополненные элементами из второго множества.
    в) разность множеств (-) – результат содержит элементы первого множества, которые не принадлежат второму.
    г) проверка эквивалентности (=) – возвращает True, если оба множества эквивалентны.
    д) проверка неэквивалентности (<>) – возвращает True, если оба множества неэквивалентны.
    е) проверка вхождения первого множества во второе ( =) – возвращает True, если второе множество включено в первое.
    з)проверка принадлежности (in) – в этой бинарной операции первый элемент – выражение, а второй – множество одного и того же типа; возвращает True если выражение имеет значение, принадлежащее множеству, (см. предыдущий пример) 1 in s1 возвращает True, а 2*2 in s2 возвращает False.
    и) Include – включает новый элемент в множество ( Include (S, I), здесь S- множество, I – элемент)
    Exclude – исключает элемент из множества ( Exclude (S, I)).

    18.Текстовый файл : описание файловой переменной, основные операции. Использование параметров программы для передачи программе имен файлов.
    Текстовый файл – совокупность строк (последовательностей символов) переменной длины, заканчивающихся специальным символом eoln (конец строки; на клавиатуре набирается нажатием клавиши Enter).
    Описание файловой переменной : : TextFile; или просто Text.
    Первоначально любой файл данных создается как текстовый. Набранные на клавиатуре данные представляют собой стандартный входной файл. Содержимое дисплея при просмотре любого файла – стандартный выходной файл. Эти файлы используются при задании и просмотре данных. Для хранения данных последние записываются в файл на внешнем запоминающем устройстве (диске).

    Основные операторы для работы с текстовыми файлами:
    assignFile( ,’ ’) – связывает файловую переменную с файлом;
    rewrite( ) – создание и открытие нового файла для записи;
    reset ( ) – открытие существующего текстового файла (файла, связанного с файловой переменной ) для чтения;
    append( ) – открытие существующего текстового файла (файла, связанного с файловой переменной ) для дозаписи в конец;
    closeFile( ) – закрытие открытого файла.

    Операторы ввода-вывода:
    read( , ) – чтение данных; элемент списка ввода для текстового файла – число или символ или строка string;
    write( , ) — запись данных согласно списку вывода; элемент списка вывода для текстового файла – число или символ или строка string.
    readln( , ) — чтение данных согласно списку ввода и переход на следующую строку; если в строке данных остались данные, не вошедшие в список ввода, они игнорируются
    writeln( , ) — запись данных в файл согласно списку вывода с добавлением в конце выведенной строки маркера конца строки (переход на следующую строку).
    Параметры :
    assignFile(dat, ParamStr(1));
    assignFile(res, ParamStr(2));
    ParamStr – стандартная функция для работы с параметрами в Delphi, она возвращает параметр с заданным номером. Ее синтаксис:
    function ParamStr( : word): string;

    Все параметры трактуются как отдельные строки (string). Параметры пользователя нумеруются, начиная с единицы. В нулевом параметре ParamStr(0) ОС передает программе полное имя запускаемого приложения (например, D:\Гречкина\Project1.exe). Этот (нулевой) параметр не входит в общее число параметров, которое можно узнать с помощью функции ParamCount: function ParamCount: word.
    19.Назначение и отличие процедур общего вида и функций.
    Назначение
    . Подпрограммы (процедуры и функции) представляет собой инструмент, с помощью которого любая программа может быть разбита на ряд в известной степени независимых друг от друга частей. Такое разбиение необходимо по двум причинам :
    1)Средство экономии памяти.
    2)Применение методики нисходящего проектирования, благодаря которой достигаются достаточно простые алгоритмы, которые можно легко запрограммировать.
    Отличие : Процедуры и функции представляют собой относительно самостоятельные фрагменты программы, оформленные особым образом и снабженные именем. Отличие процедуры от функции заключается в том, что результатом исполнения операторов, образующие тело функции, всегда является некоторое единственное значение или указатель, поэтому вызов функции, поэтому вызов функции можно использовать в соответствующих выражениях наряду с переменными и константами.
    20. Описание и вызов процедур.
    Формат описания процедуры имеет вид:

    procedure имя процедуры (формальные параметры);

    раздел описаний процедурыbegin исполняемая часть процедурыend;
    Вызов:
    имя процедуры (формальные параметры);


    21. Описание и вызов функций.
    Формат описания функции:

    function имя функции (формальные параметры):тип результата;

    раздел описаний функции

    begin
    исполняемая часть функции
    end;Вызов:
    Имя переменной:=имя функции (формальные параметры);…
    ИЛИ
    имя процедуры (имя функции (формальные параметры));
    22. Классы формальных параметров: параметры-константы, параметры-значения, параметры-переменные. Ключевые слова const, var, out при описании параметров.Параметры-значения

    Формальный параметр-значение обрабатывается, как локальная по отношению к процедуре или функции переменная, за исключением того, что он получает свое начальное значение из соответствующего фактического параметра при активизации процедуры или функции. Изменения, которые претерпевает формальный параметр-значение, не влияют на значение фактического параметра.
    Соответствующее фактическое значение параметра-значения должно быть выражением и его значение не должно иметь файловый тип или какой-либо структурный тип, содержащий в себе файловый тип.
    Фактический параметр должен иметь тип, совместимый по присваиванию с типом формального параметра-значения. Если параметр имеет строковый тип, то формальный параметр будет иметь атрибут размера, равный 255.
    Параметры-константы
    Формальные параметры-константы работают аналогично локальной переменной, доступной только по чтению, которая получает свое значение при активизации процедуры или функции от соответствующего фактического параметра. Присваивания формальному параметру-константе не допускаются. Формальный параметр-константа также не может передаваться в качестве фактического параметра другой процедуре или функции.
    Параметр-константа, соответствующий фактическому параметру в операторе процедуры или функции, должен подчиняться тем же правилам, что и фактическое значение параметра.
    В тех случаях, когда формальный параметр не изменяет при выполнении процедуры или функции своего значения, вместо параметра-значения следует использовать параметр-константу. Параметры-константы позволяют при реализации процедуры или функции защититься от случайных присваиваний формальному параметру. Кроме того, для параметров структурного и строкового типа компилятор при использовании вместо параметров-значений параметров-констант может генерировать более эффективный код.
    Параметры-переменные
    Параметр-переменная используется, когда значение должно передаваться из процедуры или функции вызывающей программе. Соответствующий фактический параметр в операторе вызова процедуры или функции должен быть ссылкой на переменную. При активизации процедуры или функции формальный параметр-переменная замещается фактической переменной, любые изменения в значении формального параметра-переменной отражаются на фактическом параметре.
    Внутри процедуры или функции любая ссылка на формальный параметр-переменную приводит к доступу к самому фактическому параметру. Тип фактического параметра должен совпадать с типом формального параметра-переменной (вы можете обойти это ограничение с помощью нетипизированного параметра-переменной).
    Примечание: Файловый тип может передаваться только, как параметр-переменная.
    23. Массивы и записи как формальные параметры процедур и функций.
    Объявление :
    Type mas = array [1..100] of integer;
    procedure massiv ( a : mas);

    Открытый массив представляет собой формальный параметр подпрограммы, описывающий базовый тип элементов массива, но не определяющий его размерности и границы
    procedure MyProc( OpenArray : array of Integer);
    Внутри такой параметр трактуется как одномерный массив с нулевой нижней границей. Верхняя граница открытого массива возвращается функцией High.Используя 0 как минимальный индекс, подпрограмма может обрабатывать одномерные массивы произвольной длины.
    24. Имена процедур и функций как фактические параметры процедур( Процедурный тип).
    Процедурные типы — это нововведение фирмы Borland (в стандартном Паскале таких типов нет). Основное назначение этих типов — дать программисту гибкие средства передачи функций и процедур в качестве фактических параметров обращения к другим процедурам и функциям.
    Для объявления процедурного типа используется заголовок процедур, в котором опускается ее имя, например:
    type
    Proc = procedure (a, b, с : Real; Var d : Real);
    Proc2 = procedure (var a, b);
    РгосЗ = procedure;
    Func1 = function : String;
    Func2 = function ( var s : String) : Real;
    В программе могут быть объявлены переменные процедурных типов, например,так:
    var
    р1 : Proc;
    ар : array [1..N] of Proc1;
    Переменным процедурных типов допускается присваивать в качестве значений имена соответствующих подпрограмм. После такого присваивания имя переменной становится синонимом имени подпрограмм.
    В отличие от стандартного Паскаля, в Турбо Паскале разрешается использовать в передаваемой процедуре как параметры-значения, так и параметры-переменные
    <ознакомиться с файлом ProcType на сайте Гречкиной>
    25.Модули в Паскале : назначение, описание, использование. Обязательные и дополнительные разделы.
    Модуль
    – это автономно контролируемая программная единица, включающая в себя различные компоненты раздела описаний ( типы, константы, переменные, процедуры и функции) и, возможно, некоторые исполняемые операторы инициализирующей части.
    Структура модуля :
    unit ;
    interface

    implementation

    begin

    end.
    Если в модуле используются другие модули, то нужно объявить их словом uses,оно можется следовать сразу за словом interface, либо сразу за словом implementation, либо и там и там.
    unit – зарезервированное слово( единица); interface – зарезервированное слово (интерфейс), начинающее интерфейсную часть модуля; implementation – зарезервированное слово(выполнение), начинающее исполняемую часть модуля; begin – зарезервированное слово, начинающее инициализирующую часть модуля(эта конструкция begin необязательна); end – зарезервированное слово, являющееся признаком конца модуля.
    В части interface содержатся объявления всех глобальных объектов модуля, которые должны стать доступными основной программе и(или) другим модулям.
    В части implementation содержит описания подпрограмм, объявленных в интерфейсной части. В ней могут объявляться локальные для модуля объекты – вспомогательные типы, константы, переменные и блоки, а так же метки, если они используются в инициализирующей части.
    В инициализирующей части (begin как это слово, так и вся эта часть может отсутствовать или быть пустой) размещаются исполняемые операторы, содержащие некоторый фрагмент программы. Эти операторы исполняются до передачи управления основной программе и обычно используются для подготовки ее к работе. Например, в них могут инициализироваться переменные, открываться нужные файлы и т.д.
    Для использования в программе модуля или списка модулей необходимо в начале программы поместить оператор uses, после которого уже указывать модули :
    program Lalala;
    uses aUnit, bUnit, cUnit;
    26.Составление функциональных и структурированных тестов.
    Функциональные тесты проверяют правильность работы программы по принципу: «не знаю как сделано, но знаю, что должно быть в результате, и именно это и проверяю».
    К функциональным тестам относятся:
    · «тепличные», проверяющие программу при корректных, нормальных значениях исходных данных
    · «экстремальные» («стресс–тесты»), находящиеся на границе области определения (например, наибольшая или наименьшая нагрузка системы по количеству или по времени), проверяющие поведение системы в экстремальных ситуациях, которые могут произойти и на которые программа должна корректно реагировать.
    · «запредельные» («тесты обезьяны»), выходящие за границы области определения (а возможно, и здравого смысла), проверяющие ситуации, бессмысленные с точки зрения постановки задачи, но которые могут произойти из-за ошибок пользователя (корректная реакция системы на запрещенный или неподдерживаемый ввод и т.п., так называемая «защита от дурака»)
    Структурные тесты контролируют (тестируют) работу всех структурных частей программы (функций, процедур, модулей, основной программы) по всем возможным маршрутам (ветвям программы).
    При структурном тестировании необходимо осуществлять контроль:
    · обращений к данным (т.е. проверять правильность инициализации переменных; а также размеры массивов и строк; отслеживать, не перепутаны ли строки со столбцами; соответствуют ли входных и выходных значений выбранным типам данных; проверять правильность обращения к файлам и т.п.);
    · вычислений (порядок следования операторов и запись выражений; переполнение разрядной сетки или получение машинного нуля; соответствие результата заданной точности и т.п.);
    · передачи управления (завершение циклов, функций, программы);
    · межмодульных интерфейсов (списки формальных и фактических параметров; отсутствие побочных эффектов, когда подпрограмма изменяет аргументы, которые не должны меняться и т.п.).
    Искусство тестирования сводится к разработке простого, полного и не избыточного набора тестов, а технология тестирования – к испытанию программы на всем наборе тестов, после внесения в нее каждого изменения.
    20. Нисходящее и восходящее тестирование программ. Достоинства и недостатки. Использование заглушек и драйверов.
    Восходящее тестирование.

    При восходящем подходе программа собирается и тестируется снизу вверх. Только модули самого нижнего уровня (модули, не вызывающие других модулей) тестируются независимо, автономно. После того как тестирование этих модулей завершено, вызов их должен быть так же надежен, как вызов встроенной функции языка или оператор присваивания. Затем тестируются модули, непосредственно вызывающие уже проверенные. Эти модули более высокого уровня тестируются не автономно, а вместе с уже проверенными модулями более низкого уровня. Процесс повторяется до тех пор, пока не будет достигнута вершина. Здесь завершаются и тестирование модулей, и тестирование сопряжений программы. Для каждого модуля необходимо написать небольшую ведущую программу.

    Использование процедур и функций в Delphi

    Скобки

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

    Возможность перегрузки

    Впервые концепция перегрузки процедур и функций была реализована в Delphi 4. Она позволяет иметь несколько различных процедур и функций с одинаковыми именами, но с разными списками параметров. Такие процедуры и функции должны быть описаны с применением директивы overload.

    procedure Test (I: integer); overload;
    procedure Test (S: string); overload;
    procedure Test (D: double); overload;

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

    Передача параметров

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

    Передача параметров по значению

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

    procedure Test(s: string);

    При вызове указанной процедуры будет создана копия передаваемой ей в качестве параметра строки s, с которой и будет работать процедура Test. При этом все внесенные в строку изменения никак не отразятся на исходной переменной s.

    Однако это не относится к объектам. Например, если в функцию передается переменная (а точнее экземпляр объекта) TStringList, то в данном случае произойдет передача по ссылке (даже если это не указано явно). Этот способ передачи является у большинства самым излюбленным, но в тоже время является и самым не практичным, т.к. для выполнения метода выделяется дополнительная память для создания точной копией передаваемой переменой. Для решения этой проблемы следует использовать один из способов описанных ниже.

    Передача параметров по ссылке

    Pascal позволяет также передавать параметры в функции или процедуры по ссылке — такие параметры называются параметрами-переменными. Передача параметра по ссылке означает, что функция или процедура сможет изменить полученные значения параметров. Для передачи параметров по ссылке используется ключевое слово var, помещаемое в список параметров вызываемой процедуры или функции.

    procedure ChangeMe(var x: longint);
    begin
    x := 2; // Параметр х изменен вызванной процедурой
    end;

    Вместо создания копии переменной x, ключевое слово var требует передачи адреса самой переменной x, что позволяет процедуре непосредственно изменять ее значение.

    Передача параметров констант

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

    procedure Test(const s: string );

    Передача открытых массивов

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

    function AddEmUp(A: array of integer): integer;

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

    Для получения информации о фактически передаваемом массиве параметров в функции или процедуре могут использоваться функции High, Low и SizeOf.

    Object Pascal также поддерживает тип array of const, который позволяет передавать в одном массиве данные различных типов. Синтаксис объявления функций или процедур, использующих такой массив для получения параметров, следующий:

    procedure WhatHaveIGot( A: array of const );

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

    procedure WhatHaveIGot( [‘Text’, 10, 5.5, @WhatHaveIGot, 3.14, true, ‘c’] );

    При передаче функции или процедуре массива констант все передаваемые параметры компилятор неявно конвертирует в тип TVarRec. Тип данных TVarRec объявлен в модуле System следующим образом:

    PVarRec = ^TVarRec;
    TVarRec = record
    case Byte of
    vtInteger: (VInteger: Integer; VType: Byte);
    vtBoolean: (VBoolean: Boolean);
    vtChar: (VChar: Char);
    vtExtended: (VExtended: PExtended);
    vtString: (VString: PShortString);
    vtPointer: (VPointer: Pointer);
    vtPChar: (VPChar: PChar);
    vtObject: (VObject: TObject);
    vtClass: (VClass: TClass);
    vtWideChar: (VWideChar: WideChar);
    vtPWideChar: (VPWideChar: PWideChar);
    vtAnsiString: (VAnsiString: Pointer);
    vtCurrency: (VCurrency: PCurrency);
    vtVariant: (VVariant: PVariant);
    vtInterface: (VInterface: Pointer);
    vtWideString: (VWideString: Pointer);
    vtInt64: (VInt64: PInt64);
    end;

    Поле VType определяет тип содержащихся в данном экземпляре записи TVarRec данных и может принимать одно приведенных значений.

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

    procedure WhatHaveIGot( A: array of const );
    var
    i: integer;
    TypeStr: string;
    begin
    for i := Low(A) to High(A) do
    begin
    case A[i].VType of
    vtInteger : TypeStr := ‘Integer’;
    vtBoolean : TypeStr := ‘Boolean’;
    vtChar : TypeStr := ‘Char’;
    vtExtended : TypeStr := ‘Extended’;
    vtString : TypeStr := ‘String’;
    vtPointer : TypeStr := ‘Pointer’;
    vtPChar : TypeStr := ‘PChar’;
    vtObject : TypeStr := ‘Object’;
    vt ;
    vtW ;
    vtPW ;
    vtAnsiString : TypeStr := ‘AnsiString’;
    vtCurrency : TypeStr := ‘Currency’;
    vtVariant : TypeStr := ‘Variant’;
    vtInterface : TypeStr := ‘Interface’;
    vtW ;
    vtInt64 : TypeStr := ‘Int64’;
    end;
    ShowMessage( Format( ‘Array item %d is a %s’, [i, TypeStr] ) );
    end;
    end;

    Значения параметров по умолчанию

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

    procedure HasDefVal( s: string; i: integer = 0 );

    Подобное объявление означает, что процедура HasDefVal может быть вызвана двумя путями. В первом случае — как обычно, с указанием обоих параметров:

    procedure HasDefVal( ‘Hello’, 26 );

    Во втором случае можно задать только значение параметра s, а для параметра i использовать значение, установленное по умолчанию:

    procedure HasDefVal( ‘Hello’ );

    При использовании значении параметров по умолчанию следует помнить о нескольких приведенных ниже правилах:

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

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

    function Add( I1, I2: integer ): integer;
    begin
    Result := I1 + I2;
    end;

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

    function Add( I1, I2: integer; I3: integer = 0 ): integer;
    begin
    Result := I1 + I2 + I3;
    end;

    Директива

    Директива <$X->запрещает вызов функций как процедур (с игнорированием возвращаемого результата). По умолчанию этот режим включен (<$X+>). Так вот, запомните, использование переменной Result недопустимо при сброшенном флажке опции Extended Syntax, расположенном во вкладке Compiler диалогового окна Project Options, или при указании директивы компилятора <$X->.

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

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

    Программирование на языке Delphi. Глава 2. Основы языка Delphi. Часть 3

    Оглавление


    Программные модули


    Структура модуля

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

    После слова unit записывается имя модуля . Оно должно совпадать с именем файла, в котором находится исходный текст модуля. Например, если файл называется MathLib.pas, то модуль должен иметь имя MathLib. Заголовок модуля формируется автоматически при сохранении файла на диске, поэтому его не следует изменять вручную. Чтобы дать модулю другой заголовок, просто сохраните его на диске под другим именем.

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

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

    Блок initialization является необязательным. Он состоит из операторов и выполняется автоматически непосредственно перед запуском основной программы. Блоки инициализации подключенных к программе модулей выполняются в том порядке, в котором они упоминаются в секции uses .

    Блок finalization тоже является необязательным. Он состоит из операторов и выполняется автоматически непосредственно после завершения основной программы. Блоки завершения подключенных к программе модулей выполняются в порядке, обратном порядку подключения модулей в секции uses .

    Если модуль не нуждается в инициализации и завершении, блоки initialization и finalization можно опустить.

    В качестве упражнения давайте создадим модуль и подключим его к основной программе (для этого сначала запустите среду Delphi):


      Выберите в главном меню команду File / New. , в появившемся диалоговом окне активизируйте значок с подписью Unit и щелкните на кнопке OK (рисунок 6).

    Рисунок 6. Окно среды Delphi для создания нового модуля

    Вы увидите, что среда Delphi создаст в редакторе кода новую страницу с текстом нового модуля Unit1 (рисунок 7):

    Рисунок 7. Текст нового модуля в редакторе кода

  • Сохраните модуль под именем MathLib, выбрав в меню команду File / Save (рисунок 8):
  • Рисунок 8. Окно сохранения модуля

    Заметьте, что основная программа Console изменилась: в списке подключаемых модулей появилось имя модуля MathLib (рисунок 9). После слова in среда Delphi автоматически помещает имя файла, в котором находится модуль. Для стандартных модулей, таких как SysUtils, это не нужно, поскольку их местонахождение хорошо известно.

    Рисунок 9. Текст программы Console в окне редактора

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

    Вот как могла бы выглядеть программа, использующая модуль Math:

    После компиляции и запуска программы вы увидите на экране три числа (рисунок 10):

    Рисунок 10. Результат работы программы Console

    Стандартные модули языка Delphi

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

    К системным модулям относятся System, SysUtils, ShareMem, Math. В них содержатся наиболее часто используемые в программах типы данных, константы, переменные, процедуры и функции. Модуль System — это сердце среды Delphi; содержащиеся в нем подпрограммы обеспечивают работу всех остальных модулей системы. Модуль System подсоединяется автоматически к каждой программе и его не надо указывать в операторе uses .

    Модули визуальных компонентов (VCL — Visual Component Library) используются для визуальной разработки полнофункциональных GUI-приложений — приложений с графическим пользовательским интерфейсом (Graphical User Interface). Эти модули в совокупности представляют собой высокоуровневую объектно-ориентированную библиотеку со всевозможными элементами пользовательского интерфейса: кнопками, надписями, меню, панелями и т.д. Кроме того, модули этой библиотеки содержат простые и эффективные средства доступа к базам данных. Данные модули подключаются автоматически при помещении компонентов на форму, поэтому вам об этом заботиться не надо. Их список слишком велик, поэтому мы его не приводим.

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

    Исходные тексты стандартных модулей среды Delphi находятся в каталоге Delphi/Source.

    Область действия идентификаторов

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

    • каждый идентификатор должен быть описан перед тем, как он будет использован;
    • областью действия идентификатора является блок, в котором он описан;
    • все идентификаторы в блоке должны быть уникальными, т.е. не повторяться;
    • один и тот же идентификатор может быть по-разному определен в каждом отдельном блоке, при этом блоки могут быть вложенными;
    • если один и тот же идентификатор определен в нескольких вложенных блоках, то в пределах вложенного блока действует вложенное описание;
    • все глобальные описания подключенного модуля видны программе (подключающему модулю), как если бы они были сделаны в точке подключения;
    • если подключаются несколько модулей, в которых по-разному определен один и тот же идентификатор, то определение, сделанное в последнем подключенном модуле перекрывает все остальные;
    • если один и тот же идентификатор определен и в подключенном модуле, и в программе (подключающем модуле), то первый игнорируется, а используется идентификатор, определенный в программе (подключающем модуле). Доступ к идентификатору подключенного модуля возможен с помощью уточненного имени. Уточненное имя формируется из имени модуля и записанного через точку идентификатора. Например, чтобы в предыдущем примере получить доступ к стандартному значению числа ?, нужно записать System.Pi.

    Строки


    Строковые значения

    Строка — это последовательность символов. При программировании строковые значения заключаются в апострофы, например:

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

    Для записи отсутствующих на клавиатуре символов используется символ # , за которым следует десятичный номер символа в кодовой таблице ASCII, например:

    Строка, которая не содержит символов, называется пустой:

    Теперь, когда известно, что представляют собой строковые значения, займемся строковыми переменными.

    Строковые переменные

    Строковая переменная объявляется с помощью зарезервированного слова string или с помощью идентификатора типа данных AnsiString, например:

    Строку можно считать бесконечной, хотя на самом деле ее длина ограничена 2 ГБ. В зависимости от присваиваемого значения строка увеличивается и сокращается динамически. Это удобство обеспечивается тем, что физически строковая переменная хранит не сами символы, а адрес символов строки в области динамически распределяемой памяти (о динамически распределяемой памяти мы расскажем ниже). При создании строки всегда инициализируются пустым значением (»). Управление динамической памятью при операциях со строками выполняется автоматически с помощью стандартных библиотек языка Delphi.

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

    Символы строки индексируются от 1 до N+1, где N — реальная длина строки. Символ с индексом N+1 всегда равен нулю (#0). Для получения длины следует использовать функцию Length , а для изменения длины — процедуру SetLength (см. ниже).

    Для того чтобы в программе обратиться к отдельному символу строки, нужно сразу за идентификатором строковой переменной или константы в квадратных скобках записать его номер. Например, FriendName[1] возвращает значение ‘A’, а FriendName[4] — ‘x’. Символы, получаемые в результате индексирования строки, принадлежат типу Char.

    Достоинство строки языка Delphi состоит в том, что она объединяет в себе свойства строки самого языка Delphi и строки языка C. Оперируя строкой, вы оперируете значением строки, а не адресом в оперативной памяти. В то же время строка не ограничена по длине и может передаваться вместо C-строки (как адрес первого символа строки) в параметрах процедур и функций. Чтобы компилятор позволил это сделать, нужно, записывая строку в качестве параметра, преобразовать ее к типу PChar (тип данных, используемый в языке Delphi для описания нуль-терминированных строк языка C). Такое приведение типа допустимо по той причине, что строка всегда завершается нулевым символом (#0), который хоть и не является ее частью, тем не менее всегда дописывается сразу за последним символом строки. В результате формат строки удовлетворяет формату C-строки. О работе с нуль-терминированными строками мы поговорим чуть позже.

    Строки в формате Unicode

    Для поддержки работы со строками формата Unicode в язык Delphi имеется строковый тип данных WideString. Работа со строками типа WideString почти не отличается от работы со строками типа AnsiString; существуют лишь два отличия.

    Первое отличие состоит в представлении символов. В строках типа WideString каждый символ кодируется не одним байтом, а двумя. Соответственно элементы строки WideString — это символы типа WideChar, тогда как элементы строки AnsiString — это символы типа AnsiChar.

    Второе отличие состоит в том, что происходит при присваивании строковых переменных. Об этом вы узнаете чуть позже, прочитав параграф «Представление строк в памяти».

    Короткие строки

    Короткая строка объявляется с помощью идентификатора типа ShortString или зарезервированного слова string , за которым следует заключенное в квадратные скобки значение максимально допустимой длины, например:

    Короткая строка может иметь длину от 1 до 255 символов. Предопределенный тип данных ShortString эквивалентен объявлению string [255].

    Реальная длина строки может быть меньше или равна той, что указана при ее объявлении. Например, максимальная длина строки Friend в примере выше составляет 30 символов, а ее реальная длина — 9 символов. Реальную длину строки можно узнать с помощью встроенной функции Length . Например, значение Length(Friend) будет равно 9 (количество букв в слове Alexander).

    Все символы в строке типа ShortString пронумерованы от 0 до N, где N — максимальная длина, указанная при объявлении. Символ с номером 0 — это служебный байт, в нем содержится реальная длина короткой строки. Значащие символы нумеруются от 1. Очевидно, что в памяти строка занимает на 1 байт больше, чем ее максимальная длина. Поэтому значение SizeOf(Friend) будет равно 31.

    Обратиться к отдельному символу можно так же, как и к символу обычной строки. Например, выражения FriendName[1] и FriendName[9] возвращают соответственно символы ‘A’ и ‘r’. Значения FriendName[10] .. FriendName[30] будут случайными, так как при объявлении типизированной константы FriendName символы с номерами от 10 до 30 не были инициализированы. Символы, получаемые в результате индексирования короткой строки, принадлежат типу Char.

    Поскольку существует два типа строк: обычные (длинные) строки и короткие строки, возникает закономерный вопрос, можно ли их совмещать. Да, можно! Короткие и длинные строки могут одновременно использоваться в одном выражении, поскольку компилятор языка Delphi автоматически генерирует код, преобразующий их тип. Более того, можно выполнять явные преобразования строк с помощью конструкций вида ShortString(S) и AnsiString(S).

    Операции над строками

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

    Операция сцепления (+) применяется для сцепления нескольких строк в одну строку.

    Выражение


    Результат


    ‘Object’ + ‘ Pascal’ ‘Object Pascal’

    Операции отношения (=, <>, >, =, ‘ABCDE’ True ‘Office’ = ‘Office’ True ‘USIS’ > ‘US’ True

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

    Объявление строки


    Выражение


    Значение строки


    Name: string[6]; Name := ‘Mark Twain’; ‘Mark T’

    Допускается смешение в одном выражении операндов строкового и символьного типа, например при сцеплении строки и символа.

    Строковые ресурсы

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

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

    Использование строковых ресурсов ничем не отличается от использования строковых констант:

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

    Форматы кодирования символов

    Существуют различные форматы кодирования символов. Отдельный символ строки может быть представлен в памяти одним байтом (стандарт Ansi), двумя байтам (стандарт Unicode) и даже четырьмя байтами (стандарт UCS-4 — Unicode). Строка «Wirth» (фамилия автора языка Pascal — прародителя языка Delphi) будет представлена в указанных форматах следующим образом (рисунок 11):

    Рисунок 11. Форматы кодирования символов

    Существует также формат кодирования MBCS (Multibyte Character Set), согласно которому символы одной строки кодируются разным количеством байт (одним или двумя байтами в зависимости от алфавита). Например, буквы латинского алфавита кодируются одним байтом, а иероглифы японского алфавита — двумя. При этом латинские буквы и японские иероглифы могут встречаться в одной и той же строке.

    Стандартные процедуры и функции для работы со строками

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

    • Concat (S1, S2, . , Sn): string — возвращает строку, полученную в результате сцепления строк S1, S2, . Sn. По своей работе функция Concat аналогична операции сцепления (+).
    • Copy (S: string, Index, Count: Integer): string — выделяет из строки S подстроку длиной Count символов, начиная с позиции Index.
    • Delete (var S: string, Index, Count: Integer) — удаляет Count символов из строки S, начиная с позиции Index.
    • Insert (Source: string; var S: string, Index: Integer) — вставляет строку Source в строку S, начиная с позиции Index.
    • Length (S: string): Integer — возвращает реальную длину строки S в символах.
    • SetLength (var S: string; NewLength: Integer) — устанавливает для строки S новую длину NewLength.

    Выражение


    Значение S


    S := Concat(‘Object ‘, ‘Pascal’);‘Object Pascal’S:= Copy(‘Debugger’, 3, 3);‘bug’S := ‘Compile’; Delete(S, 1, 3);‘pile’S := ‘Faction’; Insert(‘r’, S, 2)‘Fraction’

    • Pos (Substr, S: string): Byte — обнаруживает первое появление подстроки Substr в строке S. Возвращает номер той позиции, где находится первый символ подстроки Substr. Если в S подстроки Substr не найдено, результат равен 0.

    Выражение


    Результат


    Pos(‘rat’, ‘grated’)2Pos(‘sh’, ‘champagne’)

    • Str (X [: Width [: Decimals] ], var S: string) — преобразует числовое значение величины X в строку S. Необязательные параметры Width и Decimals являются целочисленными выражениями. Значение Width задает ширину поля результирующей строки. Значение Decimals используется с вещественными числами и задает количество символов в дробной части.

    Выражение


    Значение S


    Str(-200, S);‘-200’Str(200 : 4, S);‘ 200’Str(1.5E+02 : 4, S);‘ 150’

    • Val (S: string, var V; var Code: Integer) — преобразует строку S в величину целого или вещественного типа и помещает результат в переменную V. Если во время операции преобразования ошибки не обнаружено, значение переменной Code равно нулю; если ошибка обнаружена (строка содержит недопустимые символы), Code содержит номер позиции первого ошибочного символа, а значение V не определено.

    Выражение


    Значение V


    Значение Code


    Val(‘100’, V, Code); 100 Val(‘2.5E+01’, V, Code); 25.0 Val(‘2.5A+01’, V, Code); 4

    Описанные процедуры и функции являются базовыми для всех остальных подпрограмм обработки строк из модуля SysUtils.

    • AdjustLineBreaks (const S: string): string — возвращает копию строки S, в которой все мягкие переносы строк (одиночные символы #13 или #10) заменены жесткими переносами строк (последовательность символов #13#10).
    • AnsiCompareStr (const S1, S2: string): Integer — сравнивает две строки, делая различие между заглавными и строчными буквами; учитывает местный язык. Возвращаемое значение меньше нуля, если S1 S2.
    • AnsiCompareText (const S1, S2: string): Integer — сравнивает две строки, не делая различий между заглавными и строчными буквами; учитывает местный язык. Возвращаемое значение меньше нуля, если S1 S2.
    • AnsiDequotedStr (const S: string; Quote: Char): string — удаляет специальный символ, заданный параметром Quote, из начала и конца строки и заменяет парные спецсимволы на одиночные; если специальный символ отсутствует в начале или конце строки, то функция возвращает исходную строку без изменений.
    • AnsiExtractQuotedStr (var Src: PChar; Quote: Char): string — делает то же, что и функция AnsiDequotedStr, но результат возвращается вместо исходной строки, которая имеет тип PChar.
    • AnsiLowerCase (const S: string): string — преобразует заглавные буквы строки S к строчным буквам с учетом местного языка.
    • AnsiPos (const Substr, S: string): Integer — выполняет те же действия, что и функция Pos, но в отличие от нее поддерживает работу с многобайтовой MBCS-кодировкой.
    • AnsiQuotedStr (const S: string; Quote: Char): string — преобразует строку, заменяя все вхождения специального символа, заданного параметром Quote, на парные спецсимволы, а также помещает специальный символ в начало и конец строки. Поддерживает работу с MBCS-кодировкой.
    • AnsiSameCaption (const Text1, Text2: string): Boolean — сравнивает две строки, не делая различие между заглавными и строчными буквами, а также не учитывая символ ‘&’; учитывает местный язык.
    • AnsiSameStr (const S1, S2: string): Boolean — сравнивает строки, делая различие между строчными и заглавными буквами; учитывает местный язык.
    • AnsiSameText (const S1, S2: string): Boolean — сравнивает строки, не делая различие между строчными и заглавными буквами; учитывает местный язык.
    • AnsiUpperCase (const S: string): string — преобразует все строчные буквы в заглавные; учитывает местный язык.
    • CompareStr (const S1, S2: string): Integer — выполняет сравнение двух строк, делая различие между строчными и заглавными буквами; не учитывает местный язык. Возвращаемое значение меньше нуля, если S1 S2.
    • CompareText (const S1, S2: string): Integer — выполняет сравнение двух строк, не делая различий между строчными и заглавными буквами; не учитывает местный язык. Возвращаемое значение меньше нуля, если S1 S2.
    • DateTimeToStr (const DateTime: TDateTime): string — преобразует значение даты и времени в строку.
    • DateTimeToString (var Result: string; const Format: string; DateTime: TDateTime) — преобразует значение даты и времени в строку, выполняя при этом форматирование в соответствии со значением строки Format. Управляющие символы строки Format подробно описаны в справочнике по среде Delphi.
    • DateToStr (const DateTime: TDateTime): string — преобразует числовое значение даты в строку.
    • Format (const Format: string; const Args: array of const): string — форматирует строку в соответствии с шаблоном Format, заменяя управляющие символы шаблона на значения элементов открытого массива Args. Управляющие символы подробно описаны в справочнике по среде Delphi.
    • FormatDateTime (const Format: string; DateTime: TDateTime): string — преобразует значение даты и времени в строку, выполняя при этом форматирование в соответствии со значением строки Format. Управляющие символы строки Format подробно описаны в справочнике по среде Delphi.
    • BoolToStr (B: Boolean; UseBoolStrs: Boolean = False): string — преобразует булевское значение в строку. Если параметр UseBoolStrs имеет значение False, то результатом работы функции является одно из значений ‘0’ или ‘-1’. Если же параметр UseBoolStrs имеет значение True, то результатом работы является одно из значений ‘FALSE’ или ‘TRUE’ (программист может задать другие значения; о том, как это сделать, читайте в справочнике по системе Delphi).
    • IntToHex (Value: Integer; Digits: Integer): string — возвращает шестнадцатиричное представление целого числа Value. Параметр Digits задает количество цифр результирующей строки.
    • IntToStr (Value: Integer): string — преобразует целое число Value в строку.
    • IsDelimiter (const Delimiters, S: string; Index: Integer): Boolean — проверяет, является ли символ S[Index] одним из символов строки Delimiters. Функция поддерживает работу с многобайтовой MBCS-кодировкой.
    • IsValidIdent (const Ident: string): Boolean — возвращает True, если строка Ident является правильным идентификатором языка Delphi.
    • LastDelimiter (const Delimiters, S: string): Integer — возвращает индекс последнего вхождения одного из символов строки Delimiters в строку S.
    • LowerCase (const S: string): string — преобразует все заглавные буквы строки S к строчным; не учитывает местный язык (в преобразовании участвуют лишь символы в диапазоне от ‘A’ до ‘Z’).
    • QuotedStr (const S: string): string — преобразует исходную строку в строку, взятую в одиночные кавычки; внутри строки символы кавычки дублируются.
    • SameText (const S1, S2: string): Boolean — сравнивает строки, не делая различие между строчными и заглавными буквами; учитывает местный язык.
    • SetString (var S: string; Buffer: PChar; Len: Integer) — копирует строку с типом PChar в строку с типом string. Длина копируемой строки задается параметром Len.
    • StringOfChar (Ch: Char; Count: Integer): string — возвращает строку, в которой повторяется один и тот же символ. Количество повторений задается параметром Count.
    • StringToGUID (const S: string): TGUID — преобразует строковое представление глобального уникального идентификатора в стандартный тип TGUID.
    • StrToBool (const S: string): Boolean — преобразует строку в булевское значение.
    • StrToBoolDef (const S: string; const Default: Boolean): Boolean — преобразует строку в булевское значение. В случае невозможности преобразования, функция возвращает значение, переданное через параметр Default.
    • StrToDate (const S: string): TDateTime — преобразует строку со значением даты в числовой формат даты и времени.
    • StrToDateDef (const S: string; const Default: TDateTime): TDateTime — преобразует строку со значением даты в числовой формат даты и времени. В случае невозможности преобразования, функция возвращает значение, переданное через параметр Default.
    • StrToDateTime (const S: string): TDateTime — преобразует строку в числовое значение даты и времени.
    • StrToDateTimeDef (const S: string; const Default: TDateTime): TDateTime — преобразует строку в числовое значение даты и времени. В случае невозможности преобразования, функция возвращает значение, переданное через параметр Default.
    • StrToInt (const S: string): Integer — преобразует строку в целое число. Если строка не может быть преобразована в целое число, функция генерирует исключительную ситуацию класса EConvertError (обработка исключительных ситуаций рассматривается в главе 4).
    • StrToIntDef (const S: string; Default: Integer): Integer — преобразует строку в целое число. Если строка не может быть преобразована в целое число, функция возвращает значение, заданное параметром Default.
    • StrToInt64 (const S: string): Int64 — 64-битный аналог функции StrToInt — преобразует строку в 64-битное целое число. Если строка не может быть преобразована в 64-битное число, функция генерирует исключительную ситуацию класса EConvertError (обработка исключительных ситуаций рассматривается в главе 4).
    • StrToInt64Def (const S: string; const Default: Int64): Int64 — 64-битный аналог функции StrToIntDef — преобразует строку в 64-битное целое число. Если строка не может быть преобразована в 64-битное число, функция возвращает значение, заданное параметром Default.
    • StrToTime (const S: string): TDateTime — преобразует строку в числовой формат времени. Если строка не может быть преобразована в числовой формат времени, функция генерирует исключительную ситуацию класса EConvertError (обработка исключительных ситуаций рассматривается в главе 4).
    • StrToTimeDef (const S: string; const Default: TDateTime): TDateTime — преобразует строку в числовой формат времени. В случае ошибки преобразования, функция возвращает значение, заданное параметром Default.
    • TimeToStr (Time: TDateTime): string — преобразует числовое значение времени в строку.
    • Trim (const S: string): string — возвращает часть строки S без лидирующих и завершающих пробелов и управляющих символов.
    • Trim (const S: WideString): WideString — Unicode-аналог функции Trim — возвращает часть строки S без лидирующих и завершающих пробелов и управляющих символов.
    • TrimLeft (const S: string): string — возвращает часть строки S без лидирующих пробелов и управляющих символов.
    • TrimLeft const S: WideString): WideString — Unicode-аналог функции TrimLeft — возвращает часть строки S без лидирующих пробелов и управляющих символов.
    • TrimRight (const S: string): string — возвращает часть строки S без завершающих пробелов и управляющих символов.
    • TrimRight (const S: WideString): WideString — Unicode-аналог функции TrimRight — возвращает часть строки S без завершающих пробелов и управляющих символов.
    • UpperCase (const S: string): string — преобразует все строчные буквы строки S в заглавные; не учитывает местный язык (в преобразовании участвуют лишь символы в диапазоне от ‘a’ до ‘z’).
    • WideFormat (const Format: WideString; const Args: array of const): WideString — Unicode-аналог функции Format, учитывающий символы местного языка, — форматирует строку в соответствии с шаблоном Format, заменяя управляющие символы в шаблоне на значения элементов открытого массива Args. Управляющие символы подробно описаны в справочнике по системе Delphi.
    • WideFmtStr (var Result: WideString; const Format: WideString; const Args: array of const) — аналог функции WideFormat. Отличие в том, что WideFmtStr возвращает результат через параметр Result, а не как значение функции.
    • WideLowerCase const S: WideString): WideString — Unicode-аналог функции LowerCase (учитывает местный язык) — преобразует все заглавные буквы строки S к строчным буквам.
    • WideSameCaption (const Text1, Text2: WideString): Boolean — Unicode-аналог функции AnsiSameCaption — сравнивает две строки, не делая различие между строчными и заглавными буквами, а также не учитывая символ ‘&’; учитывает местный язык.
    • WideSameStr (const S1, S2: WideString): Boolean — Unicode-аналог стандартной операции сравнения строк — сравнивает две строки, делая различие между строчными и заглавными буквами.
    • WideSameText (const S1, S2: WideString): Boolean — Unicode-аналог функции SameText (учитывает местный язык) — сравнивает строки, не делая различие между строчными и заглавными буквами.
    • WideUpperCase (const S: WideString): WideString — Unicode-аналог функции UpperCase (учитывает местный язык) — преобразует все строчные буквы строки S в заглавные.
    • WrapText (const Line: string; MaxCol: Integer = 45): string — разбивает текст Line на строки, вставляя символы переноса строки. Максимальная длина отдельной строки задается параметром MaxCol.
    • WrapText (const Line, BreakStr: string; const BreakChars: TSysCharSet; MaxCol: Integer): string — более мощный аналог предыдущей функции — разбивает текст Line на строки, вставляя символы переноса строки.
    • AnsiToUtf8 (const S: string): UTF8String — перекодирует строку в формат UTF8.
    • PUCS4Chars (const S: UCS4String): PUCS4Char — возвращает указатель на первый символ строки формата UCS-4 для работы со строкой, как с последовательностью символов, заканчивающейся символом с кодом нуль.
    • StringToWideChar (const Source: string; Dest: PWideChar; DestSize: Integer): PWideChar — преобразует стандартную строку к последовательности Unicode-символов, завершающейся символом с кодом нуль.
    • UCS4StringToWideString (const S: UCS4String): WideString — преобразует строку формата UCS-4 к строке формата Unicode.
    • Utf8Decode (const S: UTF8String): WideString — преобразует строку формата UTF-8 к строке формата Unicode.
    • Utf8Encode (const WS: WideString): UTF8String — преобразует строку формата Unicode к строке формата UTF-8.
    • Utf8ToAnsi (const S: UTF8String): string — преобразует строку формата UTF-8 к стандратной строке.
    • WideCharLenToString (Source: PWideChar; SourceLen: Integer): string — преобразует строку формата Unicode к стандартной строке. Длина исходной строки задается параметром SourceLen.
    • WideCharLenToStrVar (Source: PWideChar; SourceLen: Integer; var Dest: string) — аналог предыдущей функции — преобразует строку формата Unicode к стандартной строке. Длина исходной строки задается параметром SourceLen, а результат возвращается через параметр Dest.
    • WideCharToString (Source: PWideChar): string — преобразует последовательность Unicode-символов, завершающуюся символом с кодом нуль, к стандартной строке.
    • WideCharToStrVar (Source: PWideChar; var Dest: string) — аналог предыдущей функции — преобразует последовательность Unicode-символов, завершающуюся символом с кодом нуль, к стандартной строке. Результат возвращается через параметр Dest.
    • WideStringToUCS4String (const S: WideString): UCS4String — преобразует строку формата Unicode к строке формата UCS-4.

    Массивы


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

    Массив — это составной тип данных, состоящий из фиксированного числа элементов одного и того же типа. Для описания массива предназначено словосочетание array of . После слова array в квадратных скобках записываются границы массива, а после слова of — тип элементов массива, например:

    После описания типа можно переходить к определению переменных и типизированных констант:

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

    Массив может быть определен и без описания типа:

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

    Объявленные выше массивы являются одномерными, так как имеют только один индекс. Одномерные массивы обычно используются для представления линейной последовательности элементов. Если при описании массива задано два индекса, массив называется двумерным , если n индексов — n-мерным . Двумерные массивы используются для представления таблицы, а n-мерные — для представления пространств. Вот пример объявления таблицы, состоящей из 5 колонок и 20 строк:

    То же самое можно записать в более компактном виде:

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

    или в более компактной записи

    Эти два способа индексации эквивалентны.

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

    Массивы в целом участвуют только в операциях присваивания. При этом все элементы одного массива копируются в другой. Например, если объявлены два массива A и B,

    то допустим следующий оператор:

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

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

    Для массивов определены две встроенные функции — Low и High. Они получают в качестве своего аргумента имя массива. Функция Low возвращает нижнюю, а High — верхнюю границу этого массива. Например, Low(A) вернет значение 1, а High(A) — 5. Функции Low и High чаще всего используются для указания начального и конечного значений в операторе цикла for . Поэтому вычисление суммы элементов массива A лучше переписать так:

    В операциях с многомерными массивами циклы for вкладываются друг в друга. Например, для инициализации элементов таблицы, объявленной как

    требуются два вложенных цикла for и две целые переменные Col и Row для параметров этих циклов:

    Массивы в параметрах процедур и функций

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

    Функция Average принимает в качестве параметра массив известной размерности. Требование фиксированного размера для массива-параметра часто является чрезмерно сдерживающим фактором. Процедура для нахождения среднего значения должна быть способна работать с массивами произвольной длины. Для этой цели в язык Delphi введены открытые массивы-параметры. Такие массивы были заимствованы разработчиками языка Delphi из языка Modula-2. Открытый массив-параметр описывается с помощью словосочетания array of , при этом границы массива опускаются:

    Внутри подпрограммы Average нижняя граница открытого массива A равна нулю (Low(A) = 0), а вот значение верхней границы (High(A)) неизвестно и выясняется только на этапе выполнения программы.

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

    Вот пример использования функции Average:

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

    И еще одно важное замечание по поводу открытых массивов. Некоторые библиотечные подпрограммы языка Delphi принимают параметры типа array of const — открытые массивы констант . Массив, передаваемый в качестве такого параметра, обязательно конструируется в момент вызова подпрограммы и может состоять из элементов различных типов (!). Физически он состоит из записей типа TVarRec , кодирующих тип и значение элементов массива (записи рассматриваются ниже). Открытый массив констант позволяет эмулировать подпрограммы с переменным количеством разнотипных параметров и используется, например, в функции Format для форматирования строки (см. выше).

    Уплотнение структурных данных в памяти

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

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

    Заметим, что ключевое слово packed применимо к любому структурному типу данных, т.е. массиву, множеству, записи, файлу, классу, ссылке на класс.

    Множества


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

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

    Для описания множественного типа используется словосочетание set of , после которого записывается базовый тип множества:

    Теперь можно объявить переменную множественного типа:

    Можно объявить множество и без предварительного описания типа:

    В выражениях значения элементов множества указываются в квадратных скобках: [2, 3, 5, 7], [1..9], [‘A’, ‘B’, ‘C’]. Если множество не имеет элементов, оно называется пустым и обозначается как [ ]. Пример инициализации множеств:

    Количество элементов множества называется мощностью . Мощность множества в языке Delphi не может превышать 256.

    Операции над множествами

    При работе с множествами допускается использование операций отношения (=, <>, >=, in .

    Операции сравнения (=, <>). Два множества считаются равными, если они состоят из одних и тех же элементов. Порядок следования элементов в сравниваемых множествах значения не имеет. Два множества A и B считаются не равными, если они отличаются по мощности или по значению хотя бы одного элемента.

    Выражение


    Результат


    [1, 2] <> [1, 2, 3] True [1, 2] = [1, 2, 2] True [1, 2, 3] = [3, 2, 1] True [1, 2, 3] = [1..3] True

    Операции принадлежности (>=, = B равно True, если все элементы множества B содержатся в множестве A. Выражение A = [1, 2] True [1, 2] in . Используется для проверки принадлежности элемента указанному множеству. Обычно применяется в условных операторах.

    Выражение


    Результат


    5 in [1..9] True 5 in [1..4, 6..9] False

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

    можно заменить более коротким:

    Операцию in иногда пытаются записать с отрицанием: X not in S. Такая запись является ошибочной, так как две операции следуют подряд. Правильная запись имеет вид: not (X in S).

    Объединение множеств (+) . Объединением двух множеств является третье множество, содержащее элементы обоих множеств.

    Выражение


    Результат


    [ ] + [1, 2] [1, 2] [1, 2] + [2, 3, 4] [1, 2, 3, 4]

    Пересечение множеств (*) . Пересечение двух множеств — это третье множество, которое содержит элементы, входящие одновременно в оба множества.

    Выражение


    Результат


    [ ] * [1, 2] [ ] [1, 2] * [2, 3, 4] [2]

    Разность множеств (-) . Разностью двух множеств является третье множество, которое содержит элементы первого множества, не входящие во второе множество.

    Выражение


    Результат


    [1, 2, 3] — [2, 3] [1] [1, 2, 3] — [ ] [1, 2, 3]

    В язык Delphi введены две стандартные процедуры Include и Exclude, которые предназначены для работы с множествами.

    Процедура Include (S, I) включает в множество S элемент I. Она дублирует операцию + (плюс) с той лишь разницей, что при каждом обращении включает только один элемент и делает это более эффективно.

    Процедура Exclude (S, I) исключает из множества S элемент I. Она дублирует операцию — (минус) с той лишь разницей, что при каждом обращении исключает только один элемент и делает это более эффективно.

    Выражение


    Результат


    S := [1, 3]; [1, 3] Include(S, 2); [1, 2, 3] Exclude(S, 3) [1, 2]

    Использование в программе множеств дает ряд преимуществ: значительно упрощаются сложные операторы if , улучшается наглядность программы и понимание алгоритма решения задачи, экономится время разработки программы. Поэтому множества широко используются в библиотеке компонентов среды Delphi.

    Записи


    Объявление записи

    Запись — это составной тип данных, состоящий из фиксированного числа элементов одного или нескольких типов. Описание типа записи начинается словом record и заканчивается словом end . Между ними заключен список элементов, называемых полями , с указанием идентификаторов полей и типа каждого поля:

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

    Чтобы получить в программе реальную запись, нужно создать переменную соответствующего типа:

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

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

    Обращение к полям записи имеет несколько громоздкий вид, что особенно неудобно при использовании мнемонических идентификаторов длиной более 5 символов. Для решения этой проблемы в языке Delphi предназначен оператор with, который имеет формат:

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

    Допускается применение оператора присваивания и к записям в целом, если они имеют один и тот же тип. Например,

    После выполнения этого оператора значения полей записи Friend станут равными значениям соответствующих полей записи BestFriend.

    Записи с вариантами

    Строго фиксированная структура записи ограничивает возможность ее применения. Поэтому в языке Delphi имеется возможность задать для записи несколько вариантов структуры. Такие записи называются записями с вариантами . Они состоят из необязательной фиксированной и вариантной частей.

    Вариантная часть напоминает условный оператор case . Между словами case и of записывается особое поле записи — поле признака . Оно определяет, какой из вариантов в данный момент будет активизирован. Поле признака должно быть равно одному из расположенных следом значений. Каждому значению сопоставляется вариант записи. Он заключается в круглые скобки и отделяется от своего значения двоеточием. Пример описания записи с вариантами:

    Обратите внимание, что у вариантной части нет отдельного end , как этого можно было бы ожидать по аналогии с оператором case . Одно слово end завершает и вариантную часть, и всю запись.

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

    High — Функция Delphi

    От Delphi 4 к Delphi 5
    Перечислимые типы.

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

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

    Для того чтобы объявлять перечислимый тип, используйте следующий синтаксис:

    typeName = (val1. valn);

    где typeName имя перечислимого типа, val — идентификаторы.

    Например, следующее объявление:

    Suite = (Club, Diamond, Heart, Spade);

    определяет перечислимый тип, названный Иск, его возможные величины являются Клуб, Алмаз, Сердце и Лопата. К сожалению, в Object Pascal нельзя использовать кириллицу.

    Когда вы объявляете перечислимый тип, вы определяете, что каждое значение val является константой типа typeName . Если идентификаторы val используются для другой цели в пределах той же области, то происходят конфликты присваивания имен. Например, вы объявляете следующий перечислимый тип:

    TSound = (Click, Clack, Clock);

    К сожалению, выражение Click является также именем метода определенного для TControl библиотеки Delphi VCL .

    Так, если вы напишите в своем приложении следующий программный код:


    procedure TForm1.DBGrid1Enter(Sender: TObject);

    var Thing: TSound;

    Вы получите ошибку компиляции; компилятор интерпретирует Click в пределах области процедуры как ссылку на метод, щелчок по форме. Вы можете работать по-другому, квалифицируя идентификатор таким образом, что если TSound объявляется в MyUnit, вы должны использовать:

    Лучшим решением, тем не менее, является выбор имен с некоторым изменением, например:

    TSound = (tsClick, tsClack, tsClock);

    TMyColor = (mcRed, mcBlue, mcGreen, mcYellow, mcOrange);

    Answer = (ansYes, ansNo, ansMaybe);

    Т.е. вы сохраняете понятный смысл имени, но не вступаете в конфликт с системой.

    Вы можете использовать значения (val1. valn) при объявлении переменных, например:


    var MyCard: (Club, Diamond, Heart, Spade);

    Но если вы объявляете MyCard, вы не можете объявить другую переменную в пределах той же области, использующей эти постоянные идентификаторы. Так, например:


    var Card1: (Club, Diamond, Heart, Spade);

    var Card2: (Club, Diamond, Heart, Spade);

    генерирует ошибку компиляции. Но объявление


    var Card1, Card2: (Club, Diamond, Heart, Spade);

    ошибку компиляции не дает.

    Или можно объявить таким образом:


    type Suit = (Club, Diamond, Heart, Spade);

    Соответствие между значениями перечисляемого типа и порядковыми номерами этих значений устанавливается порядком перечисления: первое значение в списке получает порядковый номер 0, второе значение — порядковый номер 1 и т.д.

    Максимальное число констант перечислимого типа составляет 65536 значений, поэтому фактически перечислимый тип задает некоторое подмножество целого типа Word и может рассматриваться как компактное объявление сразу группы целочисленных констант со значениями 0, 1 и т.д.

    Пусть, например, в программе должна быть переменная Mode, в которой зафиксирован один из возможных режимов работы приложения: чтение данных, их редактирование, запись данных. Можно, конечно, определить переменной Mode тип Word и присваивать этой переменной в нужные моменты времени одно из трех условных чисел: 0 — режим чтения, 1 — режим редактирования, 2 — режим записи. Тогда программа будет содержать операторы вида


    if (Mode = 1) then .

    Через некоторое время уже забудется, что означает значение Mode, равное 1, и разбираться в таком коде будет очень сложно. А можно поступить иначе: определить переменную Mode как переменную перечислимого типа и обозначить ее возможные значения как mRead, mEdit, mWrite . Тогда приведенный выше оператор изменится следующим образом:


    if (Mode = mEdit) then .

    Конечно, такой оператор понятнее, чем предыдущий.

    Переменная перечислимого типа может определяться предложением вида:


    var Mode : (mRead, mEdit, mWrite);

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

    Тогда можно ввести в программе несколько переменных этого типа. Например:

    type TMode : (mRead, mEdit, mWrite);

    var Mode1, Mode2 : TMode;

    Для работы с перечислимыми типами имеется несколько системных подпрограмм, описанных в системном модуле Delphi.

    Подпрограмма Ord возвращает число, которое указывает на порядковый номер значения параметра среди значений типа данных.

    procedure TForm1.Button1Click(Sender: TObject);

    S := ‘Blue имеет порядковую величину ‘ + IntToStr(Ord(BLUE)) + #13#10;

    S := S + ‘Код ASCII для «c» — ‘ + IntToStr(Ord(‘c’)) + ‘ decimal’;

    MessageDlg(S, mtInformation, [mbOk], 0);

    На рисунке 1 представлен результат работы подпрограммы Ord.

    procedure Dec(var X[; N: Longint]);

    Процедура Dec уменьшает переданную в качестве параметра переменную на единицу или на значение необязательного второго параметра, т.е. уменьшает на единицу или на число N переменную.


    X
    — переменная перечислимого типа (включая Int64 ), или указатель, если позволен расширенный синтаксис.


    N
    — выражение целого типа.


    procedure TForm1.Button1Click(Sender: TObject);

    procedure Inc(var X [ ; N: Longint ] );

    Процедура Inc увеличивает переданную в качестве параметра переменную на единицу или на заданное значение.


    X
    — переменная перечислимого типа (включая Int64 ), или указатель, если позволен расширенный синтаксис.


    N
    — выражение целого типа.

    Функция Odd возвращает True, если параметр нечетное число.


    function Odd(X: Longint): Boolean;


    procedure TForm1.Button1Click(Sender: TObject);

    Canvas.TextOut(10, 10, ‘5 нечетное.’)

    Canvas.TextOut(10, 10, ‘Четное!’);

    Функция Pred возвращает значение, которое в определяемой типом данных последовательности стоит перед значением параметра; предшественник.

    X — выражение порядкового типа (включая Int64). Результат того же самого типа как предшественник X.

    Succ возвращает значение, преемника.

    X — выражение порядкового типа (включая Int64). Результат того же самого типа как X — преемник X. Не используйте Succ в процедурах записи.

    Запишите следующий программный код, для проверки этой функции:

    procedure TForm1.Button1Click(Sender: TObject);

    S := ‘Предшественник для числа 5, ‘ + IntToStr(Pred(5)) + #13#10;

    S := S + ‘Преемник числа 10, ‘ + IntToStr(Succ(10)) + #13#10;

    if Succ(RED) = BLUE then

    S := S + ‘Красный цвет предшествненник синего.’;

    MessageDlg(S, mtInformation, [mbOk], 0);

    На рисунке 2 показано выдаваемое сообщение по результатам работы этой программы.

    Low возвращает самое низкое значение в диапазоне перечислимого типа, переданного как параметр.

    High возвращает самое высокое значение в диапазоне перечислимого типа данных.

    Рассмотрим пример, использующий функции Low и High.

    function Sum( var X: array of Double): Double;

    массива всегда нулевой.>

    for I := 0 to High(X) do S := S + X[I];

    procedure TForm1.Button1Click(Sender: TObject);

    List1: array[0..3] of Double;

    List2: array[5..17] of Double;

    S, TempStr: string;

    for X := Low(List1) to High(List1) do

    for X := Low(List2) to High(List2) do

    List2[X] := X * 0.0123;

    S := ‘Sum of List1: ‘ + S + #13#10;

    S := S + ‘Sum of List2: ‘;

    MessageDlg(S, mtInformation, [mbOk], 0);

    Результат работы программы показан на рисунке 3.


    Ограниченные типы или тип-диапазон.

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

    где определено минимальное и максимальное значение типа-диапазона.

    Например, если вы объявляете перечисленный тип


    type TColors = (Red, Blue, Green, Yellow, Orange, Purple, White, Black);


    type TMyColors = Green..White;

    Здесь TMyColors включает величины: зеленый, желтый, апельсиновый, пурпурный и белый.

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

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

    В этих примерах переменная Alphabet может принимать только символы латинских букв в нижнем регистре, переменная Column принимает значения только целых чисел в диапазоне 1 — 12 (это могут быть, например, номера месяцев), переменная Day также принимает значения только целых чисел, но в диапазоне 1 — 31.

    При определении типа-диапазона необходимо руководствоваться следующими правилами:

    левое значение границы диапазона не должно превышать его правую границу;

    два символа > рассматриваются как один символ, поэтому между ними недопустимы пробелы.

    Тип-диапазон наследует все свойства своего базового типа, но с ограничениями, связанными с его меньшей емкостью. Так, по вполне понятным причинам процедуры Ord(X) и Pred(X) не всегда выполнимы.

    Рассмотрим пример с использованием процедуры Inc :


    type Percentile = 0..99;

    var I: Percentile;

    Для данного примера компилятор выдает ошибку, так как величина 100 не входит в диапазон объявленного ограниченного типа. Как вы помните, процедура Inc увеличивает переданную в качестве параметра переменную на единицу или на заданное значение.

    В стандартную библиотеку Object Pascal введены две функции, поддерживающие работу с типами-диапазонами: High(X) и Low(X).

    Ограниченные типы могут использоваться, например, для объявления размеров массивов, но и самостоятельно. В компиляторе Object Pascal имеется опция, позволяющая включить проверку диапазона при присваивании значения переменной ограниченного типа. Ее значение вы можете включить в том месте вашей программы, где вы хотите начать проверку диапазона, и выключить проверку, где захотите, опцией <$R->. Можно также включить опцию проверки в окне Project Options на странице Compiler . Это надежнее, так как опция работает только при возникновении ошибок диапазона, очевидных для компилятора, а установка опции проверки диапазона в окне Project Options действует в процессе выполнения (в режиме отладки) и при попытке присвоить переменной ограниченного типа значение, выходящее за пределы заданного диапазона, генерирует сообщение «Range check error «.

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

    Этот компонент предназначен для оформления вашего приложения. Bevel позволяет выделять группы элементов, отделять их друг от друга.


    type TBevelShape = (bsBox, bsFrame, bsTopLine, bsBottomLine, bsLeftLine, bsRightLine, bsSpacer);

    property Shape: TBevelShape;

    определяет контур компонента.


    type TBevelStyle = (bsLowered, bsRaised);

    property Style: TBevelStyle;

    определяет стиль компонента (вдавленный или выпуклый). На рисунке 4 показаны свойства компонента Bevel.

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

    Пользоваться этим компонентом достаточно просто. Поместите ScrollBox на форму и проведите размещение на управляющем элементе любых компонентов. Если очередной компонент выйдет за пределы рабочей области контейнера, то появятся полосы прокрутки (рисунок 5).


    property BorderStyle: TBorderStyle;
    определяет:

    если BorderStyle = bsNone, то компонент не имеет видимой границы обрамления;

    если BorderStyle = BsSingle, то компонент имеет видимую границу обрамления.

    Рассмотрим пример создания мультимедиа-приложения, в котором используем свойства компонента Bevel.

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

    Используя свой компьютер, вы можете получать качественное воспроизведение звука на внешних HiFi-колонках или встроенных в монитор, а также видеть прекрасную картинку, просматривая фильм.

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

    Музыкальные произведения, звуковые эффекты и записи речевой информации хранятся на носителях информации в файлах специальных форматов, среди которых чаще всего применяется формат WAV (от слова wave — волна). Для хранения видеоинформации чаще всего используются файлы с расширением AVI ( Audio-Video-Information ). Обычно аудио- и видео-файлы очень большие по объему, поэтому они размещаются на лазерных дисках.

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

    Для создания мультимедиа-приложения используется компонент Delphi, имя которого MediaPlayer со страницы System палитры компонентов. Внешне компонент выглядит как панель управления магнитофона, видеомагнитофона или музыкального центра с девятью кнопками.

    1. Запустите Delphi.
    2. Используя свойство Caption, для компонента Form1 введите заголовок «CD-проигрыватель».
    3. Поместите на форму компонент Bevel. Установите в свойстве Style значение bsRaised.
    4. На компонент Bevel поместите Label, введите заголовок «Проигрыватель компакт-дисков». Выровняйте компоненты, чтобы Label1 был посередине Bevel1.
    5. Разместите на форме еще один компонент Bevel, оставьте без изменений установленное по умолчанию свойство Style равное bsLowered .
    6. Поместите на Bevel2 компонент MediaPlayer. Создайте мультимедиа приложение для проигрывания компакт-дисков.
    7. Для этого установите свойство Device Type в значение dtCDAudio, а свойству AutoOpen установите значение True.
    8. Используя комплексное свойство VisibleButtons, установите значения btStep = False, btBack = False, btRecord = False. Благодаря этим действиям с панели будут убраны все ненужные кнопки (рисунок 6) .
    9. После запуска приложения на компиляцию можете вставить компакт-диск в устройство CD-ROM и щелчком по кнопке Play осуществить воспроизведение ваших любимых мелодий.
    10. Можете добавить в свое приложение компонент Image и внедрить картинку. Размещение компонентов можно сделать как на рисунке 7, используя при этом всплывающее меню, вызываемое щелчком правой кнопкой мыши.
    1. Марко Канту. Delphi 2 для Windows 95/NT. Москва. ООО «Малип». 1997г.
    2. Джон Матчо. Дэвид Р. Фолкнер. Delphi. Москва. БИНОМ. 1995г.
    3. Эндрю Возневич. Delphi. Освой самостоятельно. Москва. Восточная книжная компания. 1996г.
    4. К. Сурков, Д. Сурков, А. Вальвачев. Программирование в среде Delphi 2.0. Минск. 1997 г. ООО «Попурри».
    5. В.В.Фаронов. Delphi 5. Учебный курс. Москва. Издательство Нолидж. 2000 г.
    6. А. Я. Архангельский. Программирование в Delphi 5. Москва. ЗАО «Издательство Бином». 2000г.


    Владимир Скуратов

    High — Функция Delphi

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

    Вообще, существует методика программирования «сверху вниз». Методика программирования «сверху вниз» разбивает задачу на несколько более простых, которые оформляются в виде подпрограмм. Те, в свою очередь, при необходимости также делятся до тех пор, пока стоящие перед программистом проблемы не достигнут приемлемого уровня сложности (то есть простоты!). Таким образом, эта методика программирования облегчает написание программ за счёт создания так называемого скелета, состоящего из описателей подпрограмм, которые в дальнейшем наполняются конкретными алгоритмами. Пустое описание подпрограммы иначе называется «заглушкой».

    И процедуры, и функции позволяют добиться одинаковых результатов. Но разница всё же есть.

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

    Функция Delphi также позволяет выполнить всё перечисленное, но дополнительно возвращает результат в присвоенном ей самой значении. То есть вызов функции может присутствовать в выражении справа от оператора присваивания. Таким образом, функция — более универсальный объект!

    Описание подпрограммы состоит из ключевого слова procedure или function, за которым следует имя подпрограммы со списком параметров, заключённых в скобки. В случае функции далее ставится двоеточие и указывается тип возвращаемого значения. Обычная точка с запятой далее — обязательна! Сам код подпрограммы заключается в «логические скобки» begin/end. Для функции необходимо в коде присвоить переменной с именем функции или специальной зарезервированной переменной Result (предпочтительно) возвращаемое функцией значение. Примеры:

    function Имя_функции(параметры): тип_результата;
    begin
    Код функции;
    Result:= результат;
    end;

    procedure Имя_процедуры(параметры);
    begin
    Код процедуры;
    end;

    Описанная таким образом подпрограмма должна быть размещена в основной программе до первого её вызова. Иначе при компиляции получите извещение о том, что «неизвестный идентификатор. » Следить за этим не всегда удобно. Есть выход — разместить только заголовок подпрограммы там, где размещают .

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

    Теперь нужно ввести понятие локальных данных. Это данные — переменные, константы, подпрограммы, которые используются и существуют только в момент вызова данной подпрограммы. Они так же должны быть описаны в этой подпрограмме. Место их описания — между заголовком и началом логического блока — ключевым словом begin. Имена локальных данных могут совпадать с именами глобальных. В этом случае используется локальная переменная, причём её изменение не скажется на глобальной с тем же именем.
    Совершенно аналогично локальным типам, переменным, константам могут быть введены и локальные процедуры и функции, которые могут быть описаны и использованы только внутри данной подпрограммы.

    Теперь пример. Напишем программу суммирования двух чисел. Она будет состоять из Формы, на которой будет кнопка (компонент Button), по нажатию на которую будет выполняться наша подпрограмма, и двух строк ввода (компоненты Edit), куда будем вводить операнды. Начнём с процедуры.

    var
    Form1: TForm1;
    A, B, Summa: Integer;
    procedure Sum(A, B: Integer);

    procedure TForm1.Button1Click(Sender: TObject);
    begin
    A:=StrToInt(Edit1.Text);
    B:=StrToInt(Edit2.Text);
    Sum(A, B);
    Caption:=IntToStr(Summa);
    end;

    procedure Sum(A, B: Integer);
    begin
    Summa:=A+B;
    end;

    Наша процедура находится после обработчика нажатия кнопки, где осуществляется её вызов. И программа работает именно потому, что заголовок процедуры вынесен в блок описания данных. Но всё же операция суммирования в данном случае производится как-то невнятно.
    Теперь сделаем то же самое с помощью функции.

    var
    Form1: TForm1;
    A, B, Summa: Integer;
    function Sum(A, B: Integer): Integer;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
    A:=StrToInt(Edit1.Text);
    B:=StrToInt(Edit2.Text);
    Summa:=Sum(A, B); // На мой взгляд, сейчас более понятно, откуда что берётся
    Caption:=IntToStr(Summa);
    end;

    function Sum(A, B: Integer): Integer;
    begin
    Result:=A+B;
    end;

    Есть особенности в использовании в качестве параметров больших по объёму структур данных, например, массивов, состоящих из нескольких тысяч (и больше) элементов. При передаче в подпрограмму данных большого объёма могут быть большие расходы ресурсов и времени системы. Поэтому используется передача не самих значений элементов (передача «по значению», как в предыдущих примерах), а ссылки на имя переменной или константы (передача «по имени»). Достигается это вставкой перед теми параметрами, которые мы хотим передать по имени, ключевого слова var.

    function Sum(A, B: Integer; var Arr: array[1..1000000] of Integer): Integer;

    Если взглянуть на описание нашей подпрограммы и описание обработчика нажатия кнопки (это тоже подпрограмма!), который был создан Delphi, то видим, что перед именем обработчика (Button1Click) стоит TForm1. Как мы знаем, в Delphi точкой разделяется объект и его атрибуты (свойства и методы). Таким образом, Delphi создаёт Button1Click как метод объекта Form1. Причём, буква T перед объектом говорит о том, что Button1Click не просто метод объекта, а метод класса объекта. Не будем этим пока заморачиваться, а просто будем поступать также. Описав свою процедуру или функцию как метод класса TForm1, мы получаем возможность использовать в ней объекты класса без указания его имени, что гораздо удобнее. То есть, если мы используем в нашей подпрограмме какие-либо компоненты, размещённые на Форме (например, Button1), то мы пишем

    Button1.W >
    а не
    Form1.Button1.W >

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

    Описав подпрограмму как метод класса, её описание мы должны поместить туда же, куда их помещает описание класса TForm1. Смотрите сами, где находится описание процедуры Button1Click. Для этого, поставив курсор внутрь подпрограммы Button1Click, нажмите CTRL+Shift и кнопку управления курсором «Вверх» или «Вниз» одновременно. Произойдёт переход к описанию подпрограммы (чтобы вернуться обратно, повторите это действие ещё раз). Ставьте описание своей подпрограммы рядом, с новой строки. Обратите внимание, что TForm1 уже не пишется.

    Рекурсия — важное и мощное свойство процедур и функций в Delphi. Рекурсия это возможность подпрограммы в процессе работы обращаться к самой себе. Без использования рекурсии приходилось бы применять циклы, а это усложняет чтение программы. Рекурсивный вызов подпрограммы сразу проясняет смысл происходящего. Естественно, приходится следить за тем, чтобы в подпрограмме обязательно было условие, при выполнении которого дальнейшая рекурсия прекращается, иначе подпрограмма зациклится.

    Пример. Вычисление факториала

    Вычисление факториала — классическая в программировании задача на использование рекурсии. Факториал числа N — результат перемножения всех чисел от 1 до N (обозначается N!):

    Создавая программу вычисления факториала числа, мы можем применить и функции, и рекурсию. Можно скачать проект данной программы.

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

    Функции Delphi модуля System

    Модуль System

    Предлагаем список функций модуля System, используемого в среде разработки Delphi.

    Abs Предназначена для получения абсолютной величины числа
    Addr Возвращает адрес переменной, функции или процедуры
    ArcTan Арктангенс числа, возвращается в радианах
    Assigned Осуществляет проверку функциональности указателей, объектов, методов
    BeginThread Начинает отдельный поток выполнения кода
    Chr Конвертирует целое число в символ
    Concat Соединяет несколько строк в одну
    Copy Создает копию части строки или части массива
    Cos Косинус числа
    Eof Возвращает true, если позиция курсора находится в конце файла открытого с помощью Reset
    Eoln Возвращает true, если позиция курсора находится в конце строки
    Exp Выдаёт экспоненту числа
    FilePos
    FileSetDate Установка даты и времени последнего изменения файла
    FileSize Выдает размер открытого файла в записях
    GetLastError Выдаёт код ошибки последнего неудачного Windows API вызова.
    GetMem Получает указанное число байтов памяти.
    Hi Возвращает байт старшего разряда от типа Integer.
    High Возвращает самое высокое значение типа или переменной
    Int Целая часть числа с плавающей точкой
    IOResult Содержит возвращаемый код последней операции ввода/вывода
    IsMultiThread Возвращает True, если код выполняет множество потоков
    Length Возвращает число элементов в массиве или строке
    Ln Выдает натуральный логарифм числа
    Lo Возвращает младший байт целого числа (2-байтового)
    Low Возвращает самое низкое значение типа или переменной
    Odd Провеяет, является ли целое число нечетным
    Ord Порядковое значение целого числа, символа или перечисления
    ParamCount Выдает число параметров переданной текущей программе
    ParamStr Возвращается один из параметров используемых для запуска текущей программы
    Pi Математическая константа
    Pos Находит позицию одной строки в другой
    Pred Уменьшает порядковую переменную
    Random Генерирует случайное целое число или число с плавающей запятой
    Round Округление чисел с плавающей запятой до целого числа
    RunError Заканчивает программу с диалогом ошибки
    SeekEof Пропускает символы, пока не встретится конец файла
    SeekEoln Пропускает символы, пока не встретится конец текущей строки или файла
    Sin Синус числа
    SizeOf Возвращает занимаемый размер типа или переменной в байтах
    Slice Создает часть массива с параметром «Открытый Массив»
    Sqr Возвращает квадрат числа
    Sqrt Возвращает квадратный корень числа
    StringOfChar Создает строку из одного символа, повторенного много раз
    StringReplace Заменяет одну или несколько подстрок, найденных в заданной строке
    StringToWideChar Преобразует обычную строку в WideChar-буфер с завершающим 0
    Trunc Целая часть числа с плавающей запятой
    UpCase Преобразует значение Char к верхнему регистру
    WideCharToString Копирует строку WideChar, заканчивающуюся нулём, в нормальную строку
    Append Открывает текстовый файл, для добавления записей в файл (добавляет в конец файла)
    Assign Назначает дескриптор файла на бинарный или текстовый файл
    AssignFile Связывает дескриптор файла с бинарным или текстовым файлом
    BlockRead Читает блок записей данных из нетипизированного двоичного файла
    BlockWrite Записывает блок записей данных в нетипизированный двоичный файл
    Break Выполняет выход из одного цикла
    ChDir Выбор диска и директории ( папки ), в которой будет производиться работа
    Close Закрывает открытый файл
    CloseFile Закрывает открытый файл
    Continue Заставляет перейти к следующей итерации цикла
    Dec Декремент порядковой переменной
    Delete Удаляет часть символов из строки
    Dispose Очищает память на которую указывает указатель
    EndThread Заканчивает поток с кодом завершения
    Erase Стирает файл
    Exclude Исключает значение из переменной набора (множества)
    Exit Осуществляет выход из функции или процедуры
    Frac Дробная часть числа с плавающей запятой
    FillChar Заполняет раздел памяти значением байта или символа-заполнителя
    Flush Сбрасывает буферизованные данные текстового файла в файл
    GetDir Получает текущий каталог (диск плюс путь) для указанного диска.
    Halt Заканчивает программу с дополнительным диалогом.
    Inc Увеличивает порядковую переменную
    Include Включает значение во множество переменных
    Insert Вставляет строку в другую строку
    MkDir Создаёт каталог
    Move Копирует байты данных из источника в место назначения
    New Создаёт новую переменную типа указатель
    Randomize Устанавливает генератор случайного числа на следующее значение
    Read Позволяет прочитать данные из двоичного или текстового файла
    ReadLn Позволяет прочитать полную строку данных из текстового файла
    ReallocMem Позволяет изменить размер существующего блока памяти
    Reset Открывает текстовый файл для чтения, или двоичный файл для чтения/записи
    ReWrite Открывает текстовый или двоичный файл для записи
    RmDir Удаление каталога
    Seek Перемещает указатель в двоичном файле в новую позицию
    SetLength Изменяет размер строки или размер динамического массива
    SetString Копирует символы из буфера в строку
    Str Конвертирует целое число или число с плавающей точкой в строку
    Truncate Уменьшает размер файла — удаляя все данные после текущей позиции
    WriteLn Записывает законченную строку данных в текстовый файл

    Илон Маск рекомендует:  Шаблон сайта зеленых оттенков HTML, CSS, JavaScripts, 1 страница
    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL