Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.02.17;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.59 MB
Время: 0.011 c
14-53773
Сатир
2004-01-28 15:07
2004.02.17
mIRC


1-53519
h0use
2004-02-05 16:37
2004.02.17
Как запустить Thread параллельно основному потоку?


1-53469
Silver_
2004-02-07 11:38
2004.02.17
Хочу бродить по RichEdit также как и в редакторе Delphi


3-53393
Janbolat
2004-01-27 08:54
2004.02.17
Печать из базы


1-53593
Lucky[ELF]
2004-02-01 23:04
2004.02.17
Работа с динамической памятью и указателями





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский