![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Указатели\пойнтеры [D7, 95/98, ME, NT4, 2000, XP, 2003]
Антибайт © (2006-06-09 19:56:00)Приветствую.
Голову сломал над сабжем. Подскажите, чем отличается ^ от @ и от Pointer (). Почему в исходниках вижу ^a и a^. В чём разница?
В свойствах проекта есть опция
Typed @ operator. Controls the type of pointer returned by the @ operator. Corresponds to {$T}.
Что она даёт?
Я так понимаю, что указатель содержит адрес, по которому размещены данные. Но как указывается размер этих данных? Т.е.
p : pointer
ничего не говорит о размере данных.
Например, у меня есть
а := 1;
А меня просят передать указатель на эту переменную. Мне надо передавать
p := @a; ?
А если я знаю адрес
p := $22;
а меня просят передать значение переменной. Мне надо делать так
a := p^; ?
А как быть, если у меня следующая структура
type
ta = record
a : integer;
p : pointer;
....
end;
var
a : ta;
А мне надо передать указатель на a.a и взять значение a.p? Так:
p := @a.a;
b := a.p^; ?
И вообще, в чём торч от указателей? Я могу, например, указатель передать из dll? Т.е. где-то в недрах dll сохранил string, но так как просто так string мне из dll не передать, я могу передать указатель на этот string?
К вражеским источникам просьба не отсылать, я не шпрехен зе дойч.
Справка борланд ситуацию не прояснила.
Книгу для начинающих прочитал - вопрос описан поверхностно. Хотелось бы услышать мнение профи.
parovoZZ (2006-06-11 18:23:00) [1]А у меня с асмом туго...
Ihor Osov'yak (2006-06-11 13:50:00) [2]немного офтопа..
в свое время, когда разбирался со всем этим, анализировал код, что генерировал компилятор... По Ctrl_Alt_C на брекпоинте..
Но в общем то в мире персоналок я начал программировать на ассемблере, так что не знаю, приемлим ли этот способ в общем случае, но мне это очень помогало..
parovoZZ (2006-06-11 01:27:00) [3]Резюмируя всё сказанное, надо делать так
TableData := PTableData (Node.Data)^;
и
Dispose (PTableData (Node.Data));
Антибайт (2006-06-11 01:02:00) [4]Ну ладно, спасибо, хоть прояснили ситуацию.
tesseract (2006-06-10 12:07:00) [5]
> Поэтому [11] -- оно немного "не в кассу", не находите?
Да признался уже, просто я обычно создавал отдельный массив под типизированные указатели.
begin...end (2006-06-10 12:01:00) [6]> tesseract © (10.06.06 11:55) [13]
> Я имел в виду использование типизированных.
А речь шла об освобождении памяти, связанной с Node.Data, то есть с НЕтипизированным указателем. Поэтому [11] -- оно немного "не в кассу", не находите?
tesseract (2006-06-10 11:55:00) [7]
> UntypedPointer := TypedPointer;
> Dispose(UntypedPointer);
При использовании нетипизированныхуказателей, полностью подтверждаю ошибочность [11] .
Я имел в виду использование типизированных.
begin...end (2006-06-10 11:26:00) [8]> tesseract © (10.06.06 10:59) [11]
> Не факт
Другими словами, Вы утверждаете, что в случае наличия в структуре таких полей при вызове Dispose тип указателя можно не указывать явно.
ОК, голословное утверждение у Вас уже есть. Теперь дело за малым -- привести РЕАЛЬНЫЙ КОД, его подтверждающий. То есть показывающий, что никакой утечки памяти не будет.
А я пока приведу код, подтверждающий МОЮ точку зрения:
type
PRec = ^TRec;
TRec = record
A: array of Integer
end;
var
TypedPointer: PRec;
UntypedPointer: Pointer;
I: Integer;
begin
I := AllocMemSize;
New(TypedPointer);
SetLength(TypedPointer.A, 100);
UntypedPointer := TypedPointer;
Dispose(UntypedPointer);
ShowMessageFmt('Утечка: %d байт', [AllocMemSize - I])
end
tesseract (2006-06-10 10:59:00) [9]
> А во-вторых, при вызове Dispose следует явно указывать
> тип указателя:
Не факт, Dipsose и создан(в отличие) для того что-бы сначала финализировать динамические данные. В отличие от freemem. Delphi хранит размер указателя в отдельном месте.
begin...end (2006-06-10 09:26:00) [10]> Rial © (10.06.06 01:43) [6]
> Рисуешь схлопотать AV.
Даже не рискует, а гарантированно получит. Потому что адреса со столь малыми адресами (например, в Win2000 -- с 0 по $FFFF) принадлежат разделу для выявления нулевых указателей, и любое обращение к памяти по этим адресам вызовет ошибку доступа.
> New делает ни что иное, как выделение памяти под SizeOf(Структура),
> Dispose тоже учитывает размер структуры. Так что сомнения
> - прочь.
Во-первых, New не только выделяет память, но и инициализирует поля типа длинных строк или динамических массивов, если таковые имеются в структуре, для которой эта память выделяется. А во-вторых, при вызове Dispose следует явно указывать тип указателя: Dispose( PTableData(Node.Data )), иначе такие поля не будут автоматически финализированы, и получится утечка памяти.
Антибайт (2006-06-10 07:29:00) [11]Вот так
TableData := PTableData (Node.Data)^; ?
Zeqfreed (2006-06-10 04:28:00) [12]
> TableData := Node.Data^ не работает.
Очень даже работает, только надо не забывать приводить к нужному типу.
Антибайт (2006-06-10 03:38:00) [13]
> Прсто маловероятно, что по этому адресу что-либо находится.
А в общем случае? Естественно, что я подразумеваю о нормальном стечении обстоятельств.
А вот С TTReeView не понятно. Как выудить инфу из Node.Data? TableData := Node.Data^ не работает. Может нужен packed record?
Rial (2006-06-10 01:43:00) [14]
> Так ведь у меня b : integer;
Первый раз слышу. Раньше надо было говорить.
> > p := $22;а меня просят передать значение переменной. Мне
> > надо делать такa := p^; ?Вот это к добру не приведет.
>
> А в чём криминал?
Прсто маловероятно, что по этому адресу что-либо находится.
Рисуешь схлопотать AV. Да и в общем случае угадать число
с адресом сложно.
Как минимум, нужно складывать, например
rec=packed record
a,b:integer;
end;
rec.a:=10;
PInteger(@Rec.A+4)^:=18;
TableData.ID := PTableData (Node.Data)^.ID;
TableData.Table := PTableData (Node.Data)^.Table;
А смысл в копировании ?
Все же уже есть в TableData_.
На крайняк можно TableData:=TableData_^;
> А как теперь этот указатель удалить? Dispose (Node.Data)
> не даёт уверенности.
Зря. New делает ни что иное, как выделение памяти под SizeOf(Структура),
Dispose тоже учитывает размер структуры. Так что сомнения - прочь.
Антибайт (2006-06-10 01:21:00) [15]Так ведь у меня b : integer;, а a.p : pointer;
> p := $22;а меня просят передать значение переменной. Мне
> надо делать такa := p^; ?Вот это к добру не приведет.
А в чём криминал?
#######
Есть следующее:
type
PTableData = ^TTableData;
TTableData = record
ID : word;
Table : TTables;
end;
Далее, в процедуре
procedure Unknown;
var
TableData : TTableData;
TableData_ : PTableData;
begin //TrV : TTreeView;
New (TableData_);
TableData_^.ID := 0;
TableData_^.Table := Journal;
MainNode := TrV.Items.AddObject (Node, User, TableData_);//Сохранили информацию.
//Далее считываем
//А вот здесь я намудрил. Не догоняю, как проще. Хотя работает.
TableData.ID := PTableData (Node.Data)^.ID;
TableData.Table := PTableData (Node.Data)^.Table;
end;
А как теперь этот указатель удалить? Dispose (Node.Data) не даёт уверенности.
Rial (2006-06-10 00:32:00) [16]
>
> Это тот же Pointer, только типизированный. Так?
>
Да.
Просто вот так сделать компилятор не даст:
Var P:Pointer;
I:Integer;
begin
P:=@I;
If (P^=$100)then begin
...
end;
end;
Это все из -за строгого контроля типов. Возможна разадресация только
типизированного указателя (если тип данных опеределен), Т.о. компилятор
уверен, что программист делает именно то, что и хотел.
> А как же быть?
Я же говорю:
p := @a.a;
b:=a.p;
parovoZZ (2006-06-09 23:28:00) [17]
> Type PInteger=^Integer;
Это тот же Pointer, только типизированный. Так?
> p := $22;а меня просят передать значение переменной. Мне
> надо делать такa := p^; ?Вот это к добру не приведет.А мне
> надо передать указатель на a.a и взять значение a.p? Так:
> p := @a.a;b := a.p^; ?b := a.p^ - не верно. В типе и речи
> не было об указателях.Откуда домик то взялся ?Просто b:=a.
> p;
type
ta = record
a : integer;
p : pointer;
....
end;
var
a : ta;
А как же быть?
Rial (2006-06-09 21:08:00) [18]Подскажите, чем отличается ^ от @ и от Pointer ().
@ - указатель на что - либо (переменную, функцию, и т.п.)
Т.е.
Type PInteger=^Integer;
Var PI:PInteger;
I:Integer;
begin
PI:=@I;
I:=10;
Теперь PI^=10.
^Type - тип, являющийся укзазателем на тип Type.
Var^ - данные, хранящиеся по указанному адресу.
Pointer() - преобразование "влоб", т.е.
I:Integer;
P:Pointer;
P:=Pointer(I) - не указатель на I, а указатель да область данных со смещением I.
Typed @ operator.
Опция определяет, будет ли компилятор ругаться на небезопасное испльзование указателей. Т.е. приведение указателей различных типов.
Но как указывается размер этих данных?
Никак. Все заботы ложатся на совесть програмиста.
Вот в AllocMem, например, этот размер записывается в предшестующие 4 байта.
p := $22;
а меня просят передать значение переменной. Мне надо делать так
a := p^; ?
Вот это к добру не приведет.
А мне надо передать указатель на a.a и взять значение a.p? Так:
p := @a.a;
b := a.p^; ?
b := a.p^ - не верно. В типе и речи не было об указателях.
Откуда домик то взялся ?
Просто b:=a.p;
И вообще, в чём торч от указателей?
Самый сложный вопрос :((
Type
ptMyRec=^TMyRec;
TMyRec=packed record
NExt,Prev:ptMyRec;
Data:Pointer;
end;
Торч от указателей в данном случае в том, чтобы ускорить работу программы
со списком данных, если не известно заранее количество элементов, а
также необходимо быстро осуществлять удаление и бодавление данных.
Ведь что бы добавть элемент в середину массива, придется двигать все
элементы справа на одну позицию, а тут - только кинуть указатель
на следующий и предыдущий элементы.
Desdechado (2006-06-09 21:01:00) [19]Указатель - это переменная, хранящая адрес чего-то в памяти.
Бывают типизированные и безликие (Pointer).
Разницы на низком уровне между ними нет, но паскаль - язык строгих типов, поэтому появились типизированные указатели для уменьшения числа ошибок. Но их можно приводить один к другому явно, но ответственность тогда на программисте.
Есть еще операция взятия ссылки, т.е. получения адреса на что-то.
А также есть обращение по указателю, т.е. доступ к памяти, на которую указывает указатель.
И похожая операция разадресации ссылки.
Ссылка от указателя отличается мало, в основном местом использования.