Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.02.17;
Скачать: CL | DM;

Вниз

Работа с динамической памятью и указателями   Найти похожие ветки 

 
Lucky[ELF]   (2004-02-01 23:04) [0]

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

Вместо предисловия: я пишу на разных языках и так уж случилось, что Си я знаю лучше всего, но хотелось бы иметь навыки в Дельфях не меньшии. Работу со списками я начал изучать с Паскаля, поскольку так решил препод, параллельно я делал это на Сях, по выше указанной причине. До сих пор со списками проблем не было ни в одном из двух языков. А не так давно я писал динамическое хранилище на С++ - написал и все получилось и тут у меня всал вопрос как такое же реализовать на Пасе/Делфях?

Вопрос конкретно в следующем:
на Сях/С++ я написал такую функцию

int CVault ::CreateItem( void *pData, word dSize, eVaultType_t vType )
{
VaultItem_t *pItem, *newItem = new( VaultItem_t );

if ( !newItem ) // Ошибка, неудалось выделить память
return -1;

newItem->data = (byte *)new byte [dSize]; // Выделяем место под данные

if ( !newItem->data ) // Если память выделеть не удалось
{
delete newItem; // Освобождаем то под что, выделить удалось
return -1; // Выход с ошибкой
}
memcpy( newItem->data, pData, dSize ); // Копируем данные

newItem->dataSize = dSize; // Запоминаем размер данных
newItem->ID = lastID++; // Генерим ID
newItem->next = NULL; // Следующего пока нет

// Подцепляем созданный элемент к списку
if ( !rootItem )
rootItem = newItem;
else
{
if ( !vType ) // Вставка в начало списка
{
// Реализация списка
newItem->next = rootItem;
rootItem = newItem;
}
else // Вставка в конец списка
{
// Реализация очереди
pItem = rootItem;
while( pItem->next != NULL )
pItem = pItem->next;

pItem->next = newItem;
}
}

maxItem++; // Счетчик очереди надо увеличить
return newItem->ID; // Все прошло успешно
}


Вот далее для ее использования

vMainMenu.CreateItem (&newItem, sizeof (newItem));

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

sizeof (newItem) - соответсвенно объем этих данных

Вопрос как реализовать это на Дельфях?
т.е. конкретные места которые у меня вызываеют непонимание - это как передать любые данные в функцию и как эти данные скопировать в выделенную память? и еще чем выделять память
procedure New(var P: Pointer);
procedure Dispose(var P: Pointer);

или
procedure FreeMem(var P: Pointer[; Size: Integer]);
procedure GetMem(var P: Pointer; Size: Integer);

или есть еще какие нибудь?

Заранее спасибо! С уважением Lucky[ELF]!

ЗюЫю можно ссылки на ресурсы.


 
Юрий Зотов ©   (2004-02-02 00:40) [1]

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

type
PItem = ^TItem;
TItem = record // или packed record
... // произвольный набор полей
NextItem: PItem
end;

var
FirstItem: PItem = nil;

procedure CreateNewItem;
var
LastItem: PItem;
begin

// Если списка еще нет, то создаем его первый элемент
if FirstItem = nil then
begin
New(FirstItem);
FirstItem^.NextItem := nil; // Признак последнего элемента
Exit
end

// Ищем последний элемент списка
LastItem := FirstItem;
while LastItem^.NextItem <> nil do
LastItem := LastItem^.NextItem;
// Создаем новый элемент и добавляем его в конец списка.
// Этому новому элементу ставим признак последнего.
New(LastItem^.NextItem);
LastItem^.NextItem^.NextItem := nil

end;

procedure DeleteAllItems;
var
P: PItem;
begin
while FirstItem <> nil do
begin
P := FirstItem^.NextItem;
Dispose(FirstItem);
FirstItem := P
end
end;


 
Lucky[ELF]   (2004-02-02 21:58) [2]

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

int CVault ::CreateItem( void *pData, word dSize, eVaultType_t vType )
{
VaultItem_t *pItem, *newItem = new( VaultItem_t );

if ( !newItem ) // Ошибка, неудалось выделить память
return -1;

newItem->data = (byte *)new byte [dSize]; // Выделяем место под данные

if ( !newItem->data ) // Если память выделеть не удалось
{
delete newItem; // Освобождаем то под что, выделить удалось
return -1; // Выход с ошибкой
}
memcpy( newItem->data, pData, dSize ); // Копируем данные


 
jack128 ©   (2004-02-02 22:10) [3]

короче прямой перевод на Object pascal
functiom CVault.CreateItem(pData: Pointer;dSize: word; vType: eVaultType_t): integer;
var
pItem, newItem: ^VaultItem_t;
begin
New(newItem);
if newItem = nil then // Ошибка, неудалось выделить память
begin
Result := -1;
Exit;
end;
newItem^.data = AllocMem(dSize); // Выделяем место под данные
if newItem^.data <> nil then // Если память выделеть не удалось
begin
Dispose(newItem); // Освобождаем то под что, выделить удалось
Result := -1; // Выход с ошибкой
end;
memcpy(newItem^.data, pData, dSize ); // Копируем данные


 
jack128 ©   (2004-02-02 22:14) [4]

мда. Что то мя глюкнуло
вместо memcpy используй Move.
Move(pData^, newItem^.Data^, dSize);


 
Lucky[ELF]   (2004-02-02 23:43) [5]

Вот это уже лучше, обязательно попробую. Спасибо.

А есть ли возможность добраться до до определенной ячейки -ну типа как в массиве, сишка это дело понимает просто arr[index], а как такое реализуется в Дельфях?

А Move он копирует или перемещаяет?

И последнее как будет выглядет вызов этой функции?

ItemID := CVault.CreateItem (@vRec, sizeof(vRec), eList );

инересует момент передачи указателя - надо писать @ или нет? или это как-то по другому?

Спасибо! с уважением!


 
jack128 ©   (2004-02-02 23:50) [6]


> добраться до до определенной ячейки -ну типа как в массиве,
> сишка это дело понимает просто arr[index], а как такое реализуется
> в Дельфях
если arr - массив, то точно так же.


> А Move он копирует или перемещаяет?
а это не одно и тоже? ;-)


> И последнее как будет выглядет вызов этой функции?
>
> ItemID := CVault.CreateItem (@vRec, sizeof(vRec), eList
> );
именно так и выглядит.
И последнее: завтра, с утра идешь в магазин и покупаешь книжку по языку Object Pascal ;-)


 
Юрий Зотов ©   (2004-02-03 12:38) [7]

> Lucky[ELF]

Я думал, что у Вас есть вопросы по принципам. Оказалось, что они у Вас всего лишь по синтаксису. Сорри, но это несерьезно.

P.S.
За исключением одного вопроса - Move он копирует или перемещает. Который и не по синтаксису, и не по принципам, а по азбуке.


 
Lucky[ELF] ©   (2004-02-03 18:58) [8]


> jack128 © (02.02.04 23:50) [6]
>
> > добраться до до определенной ячейки -ну типа как в массиве,
>
> > сишка это дело понимает просто arr[index], а как такое
> реализуется
> > в Дельфях
> если arr - массив, то точно так же.


Нет это не массив, arr - это указатель на область памяти, например как это ->
newItem^.data = AllocMem(dSize); // Выделяем место под данные

В том то и прикол, что в Сях выделив память динамически можно "перелапатить" ее как массив, интересно как это выполнить на пасе, на сишке также это можно делать и через указатель (*pMem + x <-> pMem[x]) - в пасе должно быть что-то тоже.


> > А Move он копирует или перемещаяет?
> а это не одно и тоже? ;-)

Смутило название :), хотя ести вспомнить ASM, то там сплошь и рядом mov :) и как я мог забыть


> И последнее: завтра, с утра идешь в магазин и покупаешь
> книжку по языку Object Pascal ;-)


Ни за что! тем более по пасу! причина - просто не вижу особой необходимости, хотел было купить книгу по Delphi7+DataBase, но и на ту денег зажал ("еврейская" натура взяла свое).
нет надобности по той причине, что обычно пишу на Сях, но иногда требуется именно на Дельфях, а так как привых к Сям, то привык к его возможностям - и не знаю как некоторые выполнить на Пасе (память и указатели как раз одно из)

"Язык формирует наш способ мышления и определяет, о чем мы можем мыслить."
- Б.Л. Ворф


> Юрий Зотов © (03.02.04 12:38) [7]
> > Lucky[ELF]
>
> Я думал, что у Вас есть вопросы по принципам. Оказалось,
> что они у Вас всего лишь по синтаксису. Сорри, но это несерьезно.



Напрасно вы думаете, что это не серьезно, подобно тому как ... (см. цитату) в языке еще ОЧЕНЬ важно знать, что МОЖНО и как это выполнить а иначе никуда - это еще на первом курсе произнес мой учитель по asm"у, но я тогда тупо смотря на доску не обратил на нее внимания! :)

> P.S.
> За исключением одного вопроса - Move он копирует или перемещает.
> Который и не по синтаксису, и не по принципам, а по азбуке.


:))))
Моя глупость, моя.

Спасибо за разъяснения! так глядишь и ума наберусь.
С уважением Lucky[ELF]


 
Romkin ©   (2004-02-03 19:07) [9]

А в Delphi обычно очень мало работают с динамической памятью явно.
string & dynamic array рулят.
Например, объявляешь

type
TMyArray = array of integer;

var
MyArray: TMyArray;

begin
SetLength(MyArray, 300); //Все, есть массив от 0 до 299
//работаем с ним
end; //А вот уничтожится он, как только выйдет из области видимости

То же самое со string, только у них еще и счетчик копий есть


 
Lucky[ELF] ©   (2004-02-03 19:57) [10]


> Romkin © (03.02.04 19:07) [9]


Вот это вообще новости! обязательно возьму на заметку, так все просто, что аж не по себе!

А если дальше этот массивчик передать надо в процедуру или функцию или вернуть тогда как быть?


 
Romkin ©   (2004-02-03 20:04) [11]

Да я тут сегодня в Медии писал буквально следующее:

TCurveArray = array of TPoint;

function TCurves.PointArray(Index: integer): TCurveArray;
var
Curr: PCurve;
i, len: integer;
begin
Result := nil;
Curr := GetCurve(Index);
len := 0;
while assigned(Curr) do
begin
inc(len);
Curr := Curr^.Next;
end;
if len = 0 then exit;
SetLength(Result, len); //фактически выделяем память
Curr := GetCurve(Index);
for i := High(Result) downto Low(Result) do
with Result[i] do
begin
X := Curr^.X;
Y := Curr^.Y;
Curr := Curr^.Next;
end;
end;

//юзаем:
var
CurveArray: TCurveArray;

for CurveIndex := 0 to FCurves.Count - 1 do
with pbCurve.Canvas do
begin
Pen.Color := FCurves.Color[CurveIndex];
CurveArray := FCurves.PointArray(CurveIndex);
Polyline(CurveArray);
CurveArray := nil; //Параноик я, что поделать. На самом деле не нать
end;



 
Юрий Зотов ©   (2004-02-03 20:11) [12]

> Romkin © (03.02.04 19:07) [9]
> То же самое со string, только у них еще и счетчик копий есть

У динамических массивов он тоже есть. По крайней мере, в окне CPU он наблюдается по смещению -8. А по смещению -4 наблюдается текущая длина (кол-во элементов). Все как и в строках.

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


 
Тимохов ©   (2004-02-03 20:16) [13]


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

Если позволите уточнение?
Механизмы то теже, за исключением того, что если после копирования строк путем присвоения одной пременной другой (s1 := s2) изменить строку-копию (s1), то это не скажется на строку-прототипе (s2). А в дин. массивах изменение массива-копии, будет синхронно влиять на массив-прототип.


 
jack128 ©   (2004-02-03 20:26) [14]


> А в дин. массивах изменение массива-копии, будет синхронно
> влиять на массив-прототип.
Пока я писал, ты уже отметил эту особенность :-)

Непонятно, что мешало борланду ввести у массивов такое же поведение, как и у строк


 
Тимохов ©   (2004-02-03 20:31) [15]


> Непонятно, что мешало борланду ввести у массивов такое же
> поведение, как и у строк

Имхо это сложно. Я бы сказал не возможно. Что ты будешь делить с объектами в записях, которые являются элементами массива?


 
jack128 ©   (2004-02-03 20:38) [16]


> Что ты будешь делить с объектами в записях, которые являются
> элементами массива?
А что ты делаешь сейчас при выполнении
arr2 := Copy(arr1, 0, Length(arr1)); ? ;-)


 
Юрий Зотов ©   (2004-02-03 20:46) [17]

> jack128 © (03.02.04 20:26) [14]

В строке четко известно, чем является каждый элемент - символом. А в динамическом массиве он может быть чем угодно (см. [15]). Например, еще одним динамическим массивом - и т.д. В итоге получается произвольно сложная структура и совершенно неясно, как такую ситуацию обрабатывать.


 
Тимохов ©   (2004-02-03 20:47) [18]

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


 
Тимохов ©   (2004-02-03 20:48) [19]


> В итоге получается произвольно сложная структура и совершенно
> неясно, как такую ситуацию обрабатывать.

Рекурсивно!


 
Юрий Зотов ©   (2004-02-03 20:51) [20]

> Тимохов © (03.02.04 20:48) [19]

Это ведь всего лишь компилятор. Надо ли делать из него искуственный интеллект? Пожалуй, дороговато получится...


 
Тимохов ©   (2004-02-03 20:53) [21]


> Юрий Зотов © (03.02.04 20:51) [20]

Юрий!
Про рекурсию - была шутка. :)
Думаю, что посредством железных доводов, мы с Вами отстояли динамические массивы - они сделаны хорошо!


 
jack128 ©   (2004-02-03 20:55) [22]

To Юрий Зотов ©, Тимохов ©
В крайнем случае можно ограничется разрешением присваивания массивов из элемнтарных типов.


 
Romkin ©   (2004-02-03 20:57) [23]

Это как? Тут - присваивает, там - не присваивает? :))) Бедный программист


 
Тимохов ©   (2004-02-03 21:01) [24]


> jack128 © (03.02.04 20:55) [22]

Думаю вы все-таки не очень правы.
Поставте себя на место компилятора - ужас!


 
jack128 ©   (2004-02-03 21:02) [25]


> Это как? Тут - присваивает, там - не присваивает? :))) Бедный
> программист
нет, я имел в виду вообще запретить присваивание для дин массивов из неэлментарных типов. (например как запрещается создавать типизированные файлы из длинных строк)


 
Юрий Зотов ©   (2004-02-03 21:03) [26]

> Тимохов © (03.02.04 20:53) [21]

Думаю, таки да, действительно хорошо. А строки, IMHO, в Delphi вообще сделаны прекрасно. По крайней мере, намного эффективнее и удобнее, чем просто ASCIIZ.

> jack128 © (03.02.04 20:55) [22]

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


 
jack128 ©   (2004-02-03 21:05) [27]


> Тимохов © (03.02.04 21:01) [24]
??? Что сложного? Ограничения по определенных синтаксических конструкций изходя из типов переменных в языке уже есть (см типизированные файлы из длинных строк).
Вроде распарсерить тип элементов дин массива и определить входят ли туда объекты - не так сложно.


 
Тимохов ©   (2004-02-03 21:09) [28]


> jack128 © (03.02.04 21:05) [27]

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

Создал массив записей из простых типов, все круто - копируется.
Потом при модернизации проги добавил в запись не простой тип (например, объект). Нажимаешь ф9, и кирдык. Лазь потом по коду, и вставляй копирование массивов. Оно вам надо?


 
Юрий Зотов ©   (2004-02-03 21:12) [29]

> jack128 © (03.02.04 21:05) [27]

> Вроде распарсерить тип элементов дин массива и определить
> входят ли туда объекты - не так сложно.

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

var
A: array of Integer;
...
SetLength(A, ...);
A[0] := Integer(TMyObject.Create);


 
jack128 ©   (2004-02-03 21:12) [30]

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

Создал типизированный файл записей из простых типов, все круто - копируется.
Потом при модернизации проги добавил в запись не простой тип (например, объект). Нажимаешь ф9, и кирдык. Оно вам надо?

Заметь я заменил лишь пару слов ;-)


 
jack128 ©   (2004-02-03 21:16) [31]


> A[0] := Integer(TMyObject.Create);
Некорктный пример. При явном приведении типов программист берез всю ответственность на себя. При приваивании - компилятор должен обеспечить логичное поведение операндов(не уверен, что правильно использовал слово, поясню например при a := b логично, что содержимое b копируется в a. Если по техническим причинам это сложно реализовать, то крмпилятор должен сообщить об ошибке)


 
jack128 ©   (2004-02-03 21:18) [32]

небольшое исправление

> jack128 © (03.02.04 21:12) [30]
> А вот предствте каково бы жилось кодерам.
>
> Создал типизированный файл записей из простых типов, все
> круто - копируется.
> Потом при модернизации проги добавил в запись не простой
> тип (например, длинную строку). Нажимаешь ф9, и кирдык. Оно вам
> надо?
>


 
Юрий Зотов ©   (2004-02-03 21:20) [33]

> jack128 © (03.02.04 21:16) [31]

Хорошо, другой пример: array of Pointer. Этот Pointer может указывать вообще на что угодно, на любую структуру данных.


 
jack128 ©   (2004-02-03 21:24) [34]


> Юрий Зотов © (03.02.04 21:20) [33]
и что? при приваивании логично скопировать указатели. Это что, сложно реализовать? Непонял пример...


 
Юрий Зотов ©   (2004-02-03 22:12) [35]

> jack128 © (03.02.04 21:24) [34]

Указатель может прямо или косвенно указывать на данные с управляемым временем жизни. Как быть при копировании указателя - увеличивать счетчик ссылок на эти данные, или нет? И не менее (если не более) сложная задача - а как вообще распознать, что нетипизированный указатель ссылается на такие данные?


 
jack128 ©   (2004-02-03 22:32) [36]


> Юрий Зотов © (03.02.04 22:12) [35]


> Как быть при копировании указателя - увеличивать счетчик
> ссылок на эти данные, или нет?
А разве такое где то есть? Нет, конечно. Когда это копирование УКАЗАТЕЛЯ приводило к какому либо изменению самих данных?
s: string;
P1, P2: PString;
begin
P1 := @s;
P2 := P1; // Увеличение счетчика ссылок не происходит, так почему оно должно происходить при присваивании массивов array of PString??
end;


 
Kris   (2004-02-03 23:46) [37]

Удалено модератором
Примечание: IMHO, уважаемый - это оффтоп...


 
Юрий Зотов ©   (2004-02-04 00:19) [38]

> jack128 © (03.02.04 22:32) [36]

> А разве такое где то есть? Нет, конечно.

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

Смещение Содержимое
-8 Счетчик строк - ссылок на адрес со смещением 0
-4 Длина тела строки в байтах
0 Начало тела строки (кончается оно символом #0)

Для длинных строк характерен такой пример.

var
S1, S2: string;
begin
S1 := "Вася";

// Теперь S1 указывает на байт, содержащий букву "В".
// Находится этот байт в динамической памяти и
// по смещению -8 от него будет записано число 1.
S2 := S1;
// Копия тела строки не создается, а вместо этого происходит
// копирование адреса. Теперь S2 содержит в себе тот же адрес,
// что и S1, но по смещению -8 от него уже будет записано число 2

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

Совершенно то же самое и с динамическими массивами.
var
A1, A2: array of Integer;
begin
SetLength(A1, 10);

// Теперь A1 указывает на байт в динамической памяти, с
// которого начинается тело массива. По смещению -8 от этого
// байта будет записано число 1.
A2 := A1;
// Копия тела массива не создается, а вместо этого происходит
// копирование адреса. Теперь A2 содержит в себе тот же адрес,
// что и A1, но по смещению -8 от него уже будет записано число 2

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

Все это легко и наглядно проверяется в окне CPU. Да и в книгах есть (и даже частично описано в справке).

Так вот, для случая массива нетипизированных указателей
array of pointer
компилятор никак не может узнать, что же именно записывается в элемент массива при его присваивании. А вдруг туда пишется адрес строки? или еще одного динамического массива? Тогда он должен увеличивать счетчик ссылок в этой строке или массиве. А вдруг нет? Тогда не должен. Вот и получается, что компилятор не может распознать, что же ему делать. Соответственно, он и не сможет построить гарантированно правильный код.


 
Piter ©   (2004-02-04 00:56) [39]

>Вот это вообще новости! обязательно возьму на заметку, так все просто, что аж не по себе!

Вот вот! Я всегда говорил, что Сишники ругают Дельфи из-за того, что Дельфи то они и не знают!

P.S. А если честно - здесь столько нафлудили, что автор ветки, видимо, не вернется...


 
Kris   (2004-02-04 07:18) [40]


> Kris (03.02.04 23:46) [37]
> Удалено модератором
> Примечание: IMHO, уважаемый - это оффтоп...


Спасибо товаришь модератор! теперь вместо одного вопроса у меня появилось два. оказвыается я не знаю не ИМХО ни оффтоп. Спасибо еще раз помогли



Страницы: 1 2 вся ветка

Текущий архив: 2004.02.17;
Скачать: CL | DM;

Наверх




Память: 0.6 MB
Время: 0.022 c
1-53606
Xizzy
2004-02-07 16:49
2004.02.17
изменить memo


1-53551
Karlson
2004-02-05 13:23
2004.02.17
компонент FormStorage библиотеки RxLib


1-53556
senya
2004-02-05 11:30
2004.02.17
Как не обновлять DBGrid во время выполнения добавления строк


4-53815
Avenger_NhT
2003-12-09 15:18
2004.02.17
включение TV-OUT


7-53785
MaximCHR
2003-10-31 15:58
2004.02.17
блокировка клавиатуры и мыши