LongDayNames — Переменная Delphi


Содержание

Delphi: имена динамических переменных?

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

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

Началом кода, первым шагом является определение количества URL-адресов в текстовом блоке. Я делаю это, используя функцию «копировать» от начала до конца текстового блока, ища тег «a href=».

Это прекрасно работает.

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

Я бы хотел избежать таких вещей.

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

То, что я себе представлял, было следующим:

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

Когда исправление патерна фиксировано, я представил себе это:

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

Но, конечно, это не работает :)

Мой вопрос :

Кто-нибудь из вас видит решение?

Я осужден на запись длинной последовательности «если», или могу ли я динамически изменять имена переменных в цикле?

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

Delphi: динамические имена переменных?

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

Мой вопрос может показаться странным, даже newbish, но я строй приложения для разбора строк текста с URL.

Начало кода, первый шаг, чтобы определить, сколько ссылок есть в текстовом блоке. Я делаю это с помощью функции «копировать» от начала до конца текстового блока, ищет тег «A HREF =» тег.

Это прекрасно работает.

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

То, что я хотел бы избежать вещи, как это .

. потому что с максимумом 5 URL возможно в текстовом блоке, который дал бы мне veryyyyy длинного кода.

То, что я представлял себе это было:

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

Как синтаксический лаковой фиксирована, я представлял себе это:

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

Но, конечно, это не работает :)

Мой вопрос :

Кто-нибудь из вас видит выход из этого?

Могу ли я осуждал к написанию «если затем» длинную последовательность, или я могу динамически изменять имена переменных через петлю?

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

LongDayNames — Переменная Delphi

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

Dispose Высвобождает память из-под динамической переменной.
Finalize Деинициализирует динамическую переменную.
FreeMem Высвобождает память из-под динамической переменной.
GetMem Создает динамическую переменную, выделяя под нее указанный объем памяти.
Initialize Инициализирует динамическую переменную.
New Создает динамическую переменную.
ReallocMem Перераспределяет память для динамической переменной.
Процедура Dispose( var P: Pointer);

Описание:
Процедура высвобождает область памяти, которую использует динамическая переменная P. Значение указателя P в данном случае становится неопределенным. Если функции передан недопустимый указатель, то возникает исключение EInvalidPointer. Обработка ошибок с помощью механизма обработки исключительных ситуаций включается директивой компилятора <$I+>.

Пример: Процедура Finalize( var V [; Count: Integer] );

Описание:
Процедура деинициализирует динамическую переменную, указанную в параметре V. Данная процедура должна использоваться только в тех случаях, когда для высвобождения памяти из-под динамической переменной не используется процедура Dispose. Для объектов глобальных, локальных и динамических переменных при высвобождении памяти с помощью стандартной процедуры Dispose, компилятор генерирует код, завершающий работу с длинными строками, переменными типа Variant и интерфейсами после разрушения переменной. Если память, содержащая не пустые или не инициализированные длинные строки, Variant-переменные или интерфейсы, высвобождается не при помощи процедуры Dispose (например, процедурой FreeMem), то перед высвобождением памяти требуется вызвать процедуру Finalize для того, чтобы закрыть указанную переменную. Процедура Finalize присваивает всем длинным строкам пустое значение, а переменные типа Variant и интерфейсы деинициализирует (устанавливает тип Unassigned). Дополнительный параметр Count может быть определен в тех случаях, когда необходимо высвободить память, из-под нескольких переменных, содержащихся в непрерывном блоке памяти (например, динамически распределенный массив строк) для того, чтобы закрыть все переменные одной операцией. Если переменная, определенная в параметре V не содержит длинных строк, Variant-значений и интерфейсов, то компилятор просто игнорирует вызов процедуры.

Пример:
См. пример к функции FreeMem.

Процедура FreeMem( var P: Pointer [; Size: Integer] );

Описание:
Процедура уничтожает переменную, с которой связан указатель P и высвобождает память, занимаемую данной переменной. В необязательном параметре Size указывается объем памяти в байтах, выделенный ранее динамически под переменную. Если после действия процедуры FreeMem, вызвать указатель P, то возникнет ошибка, т.к. указатель имеет неопределенное значение.

Пример: Процедура GetMem( var P: Pointer; Size: Integer );

Описание:
Процедура создает динамическую переменную: выделяет блок памяти размером Size байт под переменную, указанную в параметре P, и возвращает указатель на начало данного блока памяти. Параметр P может представлять собой любой тип указателя. Указатель на новую созданную переменную записывается как P^. Если для создания динамической переменной недостаточно памяти, то возникает исключение EOutOfMemory.

Пример:
См. пример к функции FreeMem.

Процедура Initialize( var V [ ; Count: Integer] );

Описание:
Процедура инициализирует динамическую переменную. Если динамическая переменная была создана не с помощью процедуры New, а другим способом (например, с помощью процедуры GetMem или процедуры ReallocMem), то после создания переменной, ее необходимо инициализировать процедурой Initialize. При вызове данная процедура обнуляет память, занятую длинными строками Variant-значениями и интерфейсами. Длинным строкам присваивается пустое значение, а для Variant-значений и интерфейсов устанавливается неопределенный тип (Unassigned). Необязательный параметр Count может быть определен, когда память под несколько переменных выделена в непрерывном адресном пространстве. Это позволяет инициализировать все переменные одним вызовом процедуры. Если переменная, определенная в параметре V не содержит длинных строк, Variant-значений и интерфейсов, то компилятор игнорирует данный вызов процедуры и не генерирует ни какого кода.

Процедура New( var P: Pointer );

Описание:
Процедура создает новую динамическую переменную, и ассоциирует с ней указатель P. Параметр P может представлять собой любой тип указателей. Размер памяти, выделяемый под переменную, зависит от типа указателя. Новая созданная переменная может быть вызвана как P^. Если для создания динамической переменной недостаточно памяти, то возникает исключение EOutOfMemory. По завершению использования динамической переменной память, выделенную ранее процедурой New, необходимо высвободить вызовом процедуры Dispose.

Пример:
См. пример к функции Dispose.

Процедура ReallocMem( var P: Pointer; Size: Integer );

Описание:
Процедура перераспределяет память размером Size байт под динамическую переменную P. При вызове данной процедуры указатель P должен иметь значение nil или должен указывать на динамическую переменную, память под которую была предварительно выделена с помощью процедур GetMem или ReallocMem.Если P = nil, Size = 0, то процедура не производит никаких действий.Если P = nil, а Size <> 0, то процедура распределяет новый блок памяти размером Size и устанавливает указатель P на начало блока. Такой вызов процедуры аналогичен обращению к процедуре GetMem. Если P <> nil, а Size = 0, то процедура высвобождает блок памяти, на который указывает P и устанавливает P = nil. Вызов процедуры с указанными параметрами аналогичен обращению к процедуре FreeMem, но в отличие от FreeMem процедура ReallocMem очищает указатель.

Илон Маск рекомендует:  Что такое код openssl_pkcs7_decrypt

Длинные строки и динамические массивы в Delphi

Автор: Вишневский Павел
http://www.nsk.su/

Опубликовано: 12.12.2004
Исправлено: 13.03.2005
Версия текста: 1.0

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

ПРИМЕЧАНИЕ

В данной статье речь по сути идет о Delphi версии 7 и ниже. В Delphi.NET все, что связано с массивами и строками основано на .NET Framework и можно говорить скорее об эмуляции поведения массивов и строк. Их реализация же совершенно отличается от того, что было в Delphi прошлых версий. – прим.ред

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

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

Реализуемый компилятором код выглядит приблизительно так:

Что показывает приведенный пример:

  1. Переменная I, имеющая значение типа Integer, расположена в стеке и содержит случайный мусор. В отличие от переменной простого типа, для переменных S и A (являющихся указателями, также располагающимися в стеке), компилятор всегда вставляет код, инициализирующий их в nil .
  2. При присваивании длинным строкам значений или изменении размера массива компилятор вставляет код, динамически выделяющий область памяти, и присваивает указатель на нее этой переменной. То есть само содержимое строки или массива располагается в динамической памяти.
  3. Перед выходом из процедуры компилятор вставляет специальные функции финализации, ответственные за освобождение выделенной динамической памяти.
  4. И, наконец, компилятор заменяет почти все операции с этими переменными на свои системные функции.

Реализация

В начале выделяемой области памяти содержится заголовок, используемый системными функциями Delphi (определен в System.pas ) для управления переменными обсуждаемых типов. Заголовок описывается записью TPvsDynRec. Вот ее описание:

Для строк и массивов использование полей этой структуры несколько отличается, но сам принцип одинаковый. Вот описание этих полей:

  • sizeFlags содержит размер памяти и некоторые флаги. Это поле прямо никак не связано ни со строкой или массивом, а относится к распределению памяти.
  • refCnt – счетчик ссылок.
  • length — длина строки, или количество элементов массива. Это значение возвращается функцией Length .

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

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

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

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

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

Длинные строки

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

Если происходит присваивание локальной переменной:

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

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

Любое изменение строки заменяется на вызов системных функций. Если счетчик строки в этот момент не равен 1 , создается новая строка. Исключением из этого правила является доступ к содержимому строки по указателю (приведение к типу PChar). В этом случае уже ничего не контролируется. Ниже приведены два примера, иллюстрирующих такое поведение.

К изменению строки через PChar нужно относится с осторожностью. Рассмотрим код:

Это код правильно скомпилируется, но при выполнении выдаст ошибку нарушения доступа. Причина в том, что строка S ( refCnt = -1 ) находится в сегменте памяти, защищенном от записи.

Поэтому казалось бы, безобидная процедура:

вызовет ошибку нарушения доступа при передаче в нее строки с refCnt = -1.

Чтобы получить уникальную ссылку для строки, состоящей из некоторой последовательности символов, можно воспользоваться функцией UniqueString. Это позволяет ускорить вычисления со строками, так как при этом можно будет сравнивать строки, просто сравнивая указатели на них. У таких строк refCnt всегда равен 1 .

Динамические массивы

В отличие от строк, динамический массив не может инициализироваться литералами, поэтому он не может иметь refCnt, равный -1 . Причем Delphi уже не контролирует изменение содержимого массива, а создает новый массив только при попытке изменения его размера (причем даже если сам размер не меняется), если refCnt > 1 .

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

После выполнения E8 переданная строка не изменится, так как при S[1] := ‘t’ будет создана новая строка. Вызов же E9 приведет к изменению содержимого массива.

Рассмотрим более интересный пример. Пусть массив A не пуст.

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

Рассмотрим, почему так происходит. При вызове любой из этих процедур A — локальная переменная на стеке, указывающая на переданный массив. Пусть входной массив A = [0,1,2,3,4] .

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

Эта разница особенно заметна при передаче как константным параметром:

Локальная переменная Result

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

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

В данном случае сама переменная S используется как Result .

Несколько другой пример работает уже, как и ожидается.

Но реализуемый код аналогичен, только вводится временная переменная Tmp исполняющая роль Result

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

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

Переменные типа строки и динамические массивы все-таки указатели

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

Каково значение Str при вызове E16(S) из E17 ? Формально, раз параметр передается в процедуру E16 по значению, а тем более как константа, то изменение глобальной переменной S ничего не должно изменить. Но так как параметр есть только указатель, то изменение глобальной переменной S создаст новую строку, а память под старой будет освобождена (счетчик ссылок равен 1). В данном примере это неминуемо приведет к ошибке доступа к памяти. Можно привести множество подобных примеров, так что следует лучше полагаться на знание реализации таких типов данных, чем на формальные правила языка.

Хранение в переменных другого типа

Спрашивается, куда указывает P после выполнения процедуры E18 ? Естественно на мусор, так как память под строку S по выходе из процедуры будет освобождена. По этой же причине компилятор не позволяет помещать длинные строки и динамические массивы в вариантную часть записи, он просто не знает, что реально там будет и не может вставить код для управления ссылками и памятью.

Тем не менее, иногда возникает такая необходимость.

Для решения данной проблемы нужно присваивать в предыдущем примере

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

Для массива абсолютно аналогично.

Многомерные динамические массивы

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

Например, вызов SetLength(A,2,3) создает 3 массива:

  • массив A — массив указателей размерностью 2
  • два массива A[0] и A[1] — данных размерностью по 3

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

Создает треугольный массив.

Ошибка компилятора Delphi

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

При включенной оптимизации <$O+>и отключения range-checking <$R->, вызов этой функции приводил к ошибке доступа к памяти. Компилятор порождал, очевидно, ошибочный код:

Причем эта ошибка никак не связана с динамическими массивами, то же самое происходило и с функцией:

Когда в Borland узнали об этой ошибке, они ее быстро исправили и в Delphi6.2, она уже отсутствует. Для тех, кто продолжает работать с более старыми версиями, я советую обратить на это внимание. Для правильной работы функции E18 , ее следует несколько изменить:

Такой код, хоть и менее оптимально, правильно компилируется во всех версиях (я надеюсь).

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

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

  • PvsDynArrayClone – создает уникальную копию массива.
  • PvsDynArrayInsert – вставляет новые элементы в любое место массива.
  • PvsDynArrayRemove – удаляет элементы из массива.
  • PvsDynArrayJoin – копирует элементы из одного массива в другой.

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

  • PvsQuickSort – процедура быстрой сортировки для любых данных представляемых как массив.
  • PvsArrayQuickSort — процедура быстрой сортировки для любых массивов как статических, так и динамических.
  • PvsDynArrayQuickSort — процедура быстрой сортировки для динамических массивов.
  • PvsBinaryFind – процедура двоичного поиска в любом массиве.
  • PvsDynArrayBinaryFind — процедура двоичного поиска в динамическом массиве.


Несколько замечаний по применению:

  1. Одним из параметров этих функций является RTTI о типе массива, возвращаемая оператором TypeInfo. И действительно, как можно изменить размер массива, не зная размер его элемента, ведь в заголовке массива размер элемента не хранится. И это не искусственный прием, так поступает сама Delphi. Таких функций, как SetLength или Length фактически не существует, компилятор заменяет их своими системными функциями. В частности вызов SetLength транслируется в DynArraySetLength, с передачей ему RTTI.
  2. Элементами динамического массива могут быть длинные строки, интерфейсы, динамические массивы и т.п. Поэтому при удалении такого элемента требуется выполнить финализацию всех находящихся в нем значений, какой бы вложенности они небыли. Предлагаемые функции корректно выполняют финализацию.
  3. Функции полностью следуют стандартному поведению в отношении учета счетчика ссылок.
  4. Для работы с динамическими массивами используются те же системные процедуры, которые использует сама Delphi.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Динамические переменные. Delphi

Есть класс. Например:
PTC = ^TC;
TC = class
i:integer;
end;

Создаю динам переменную
new(p);
p^:=TC.create;

Освобождаю ее
Dispose(p);
или
p^.free;
или
freeandnil(p^);
Но если верить диспетчеру задач то эта переменная не освобождяется.

Что делать или как правильно освобождать динам. переменные?

класс уже является указателем. зачем ты делаешь указатель на указатель?
в твоей ситуации нужно делать сначала Free, потом Dispose

>класс уже является указателем. зачем ты делаешь указатель на указатель?
У меня будет самодельный список классов.
Этот пример как бы испытательная прощадка
>в твоей ситуации нужно делать сначала Free, потом Dispose
сейчас попробую.

Vorotnyak_Nazar
> У меня будет самодельный список классов.
и что?

@!!ex
Работает!
Большое спасибо.
Можно спросить почему это работает?

Можно спросить, почему ты делаешь вещи в которых не разобрался?

Ты два раза выделяешь память разными способами.
Сначала ты выделяешь место под указатель, потом под класс:
new(p); — тут 4 байта
p^:=TC.create; — тут sizeof(TC)
Соответственно и освобождать надо два раза.
Сначала класс, потом указатель где указатель на класс хранился.

Никаких new не нужно. Делаешь:
p:TC;
P:=TC.Create();

p — это УКАЗАТЕЛЬ на класс. УЖЕ указатель.

@!!ex
Угу. Все ясно.
Спасибо за обяснения!

Vorotnyak_Nazar
> Но если верить диспетчеру задач то эта переменная не освобождяется.

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

@!!ex
> p — это УКАЗАТЕЛЬ на класс. УЖЕ указатель.

+1 Классы в Delphi не могут быть созданны не в динамической памяти. new — это для выделения памяти под переменные встроенных типов, объекты и записи.

>+1 Классы в Delphi не могут быть созданны не в динамической памяти. new — это для выделения памяти под переменные встроенных типов, объекты и записи.
Того я і обратился что с записями все нормально, а с классом error.

0iStalker
> +1 Классы в Delphi не могут быть созданны не в динамической памяти.

В Turbo Pascal можно было работать как с динамическими, так и со статическими экземплярами объектов. В объектной модели Object Pascal программист работает только с динамическими экземплярами классов, выделяемых в heap-области (куче). В связи с этим изменен синтаксис обращения к полям и методам объектов. Ранее для работы с динамическими экземплярами объектов, проинициализированными с использованием обращения к конструктору в сочетании с функцией New, необходимо было использовать обращение «по адресу» (^). Теперь тип класса стал являться по умолчанию также указателем.

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

0iStalker
оверрайд NewInstance/FreeInstance и хоть по сети на удаленном компе создавай

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

Динамические структуры данных в Delphi

Указатели

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

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

  • имя — имя переменной-указателя;
  • тип — тип переменной, на которую указывает переменная-указатель;
  • значок ^- показывает, что объявляемая переменная является указателем.

Приведем примеры объявления указателей:

В приведенном примере переменная pi — это указатель на переменную типа integer, а р2 — указатель на переменную типа real. Тип переменной, на которую ссылается указатель, называют типом указателя. Например, если в программе объявлен указатель р: ^integer, то говорят: ^р — указатель целого типа^ или ^р — это указатель на целое^. В начале работы программы переменная-указатель ^ни на что не указывает^.

В этом случае говорят, что значение указателя равно NIL.

Зарезервированное слово NIL соответствует значению указателя, который ни на что не указывает.

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

Например, если переменные p1 и р2 объявлены как указатели, то инструкция

устанавливает значение переменной, а инструкция

проверяет, инициализирован ли указатель р2.

Указателю можно присвоить значение — адрес переменной соответствующего типа (в тексте программы адрес переменной — это имя переменной, перед которым стоит оператор @). Ниже приведена инструкция, после выполнения которой переменная р будет содержать адрес переменной n.

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

переменные pi и р2 указывают на одну и туже переменную. Указатель можно использовать для доступа к переменной, адрес которой содержит указатель.

Например, если р указывает на переменную — то в результате выполнения инструкции

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

Динамические переменные

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

Выделение памяти для динамической переменной осуществляется вызовом процедуры new. У процедуры new один параметр — указатель на переменную того типа, память для которой надо выделить. Например, если р является указателем на тип real, то в результате выполнения процедуры new(p)- будет выделена память для переменной типа real (создана переменная типаreal), и переменная-указатель р будет содержать адрес памяти, выделенной для этой переменной.

У динамической переменной нет имени, поэтому обратиться к ней можно только при помощи указателя.Процедура, использующая динамические переменные, перед завершением своей работы должна освободить занимаемую этими переменными память или, как говорят программисты, «уничтожить динамические переменные». Для освобождений памяти, занимаемой динамической переменной, используется процедура Dispose, которая имеет один параметр — указатель на динамическую переменную.

Например, если р — указатель на динамическую переменную, память для которой выделена инструкцией new ( p ) , то инструкция dispose (p) освобождает занимаемую динамической переменной память.

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

Листинг 8.3. Создание, использование и уничтожение динамических переменных

В начале работы процедура создает три динамические переменные. Две переменные, на которые указывают p1 и р2, получают значение в результате выполнения инструкции присваивания. Значение третьей переменной вычисляется как сумма первых двух.

Списки

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

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

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

Ниже приведен пример объявления компонента списка студентов:

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

Следующая программа (ее текст приведен в листинге 8.4) формирует список студентов, добавляя фамилии в начало списка. Данные вводятся в поля редактирования диалогового окна программы (рис. 8.8) и добавляются в список нажатием кнопки Добавить (Button1).

Листинг 8.4. Добавление элемента в начало динамического списка

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

Вывод списка выполняет процедура TForml.Button2Click, которая запускается нажатием кнопки Показать. Для доступа к элементам списка используется указатель curr. Сначала он содержит адрес первого элемента списка. После того как первый элемент списка будет обработан, указателю curr присваивается значение поли next той записи, на которую указывает curr.

В результате этого переменная curr содержит адрес второго элемента списка. Таким образом, указатель перемещается по списку. Процесс повторяется до тех пор, пока значение поля next текущего элемента списка (элемента, адрес которого содержит переменная curr) не окажется равно NIL.

Delphi-Help

LongDayNames

LongDayNames

Описание

var LongDayNames : array[1..7] of string;
array[1] := ‘Sunday’;
array[2] := ‘Monday’;
array[3] := ‘Tuesday’;
array[4] := ‘Wednesday’;
array[5] := ‘Thursday’;
array[6] := ‘Friday’;
array[7] := ‘Saturday’;

Переменная LongDayNames содержит массив полных строковых названий дней недели.

Так как это — массив, вы можете модифицировать значения по умолчанию (установленные регионом Windows), но это рекомендуется.

Пример кода

var
myDate : TDateTime;
day : string;

begin
myDate := EncodeDate(2002, 12, 31);

day := LongDayNames [DayOfWeek(myDate)];

ShowMessage(‘ Рождество 2002 г . — ‘+day);
end;

Рождество 2002г. — Вторник

Примечание

Предупреждение : эти значения используют Воскресенье как начальное значение. Это не является стандартом ISO 8601. Используйте с DayOfWeek, который также обрабатывает воскресенье как первый день недели.

Вам советуют использовать DayOfTheWeek, который соответсвует ISO 8601, используя Понедельник в качестве начала недели.

Динамические SQL переменные (Delphi)

4 ответа

br /> 2. А слабо посмотреть на строку запроса, которая получается в результате ваших манипуляций? При беглом взгляде на код, я предполагаю, что это будет нечто вроде

select * from auto.db where «brand»=1 where «color»=2

естественно ошибка в синтаксисе.
3. Я не вижу подставляемых переменных в вашем запросе. Вы явно подставляете в запрос значения.

1) тем что
select . from . where where неправильно, а правильно
where AND | OR
2) Чем плохо — это отдельный вопрос. Я же отвечал на ваш вопрос:
«и ещё вроде динамические(brand, color) переменные в BDE нужно описывать в param!?»

в том, что в код следует зашивать только константы, которые никогда не изменяться. типа числа Пи или е :)

Конспект

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

Страницы

четверг, 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

Илон Маск рекомендует:  Классификация элементов
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL