Форум: "Начинающим";
Текущий архив: 2007.09.02;
Скачать: [xml.tar.bz2];
ВнизData Pointer и все все все... Найти похожие ветки
← →
Салат (2007-08-06 19:40) [0]Мне стыдно но я совсем не умею работать с указателями (Pointers) :( Расскажите в двух словах чайнику как через pointer работать с переменными (желательно на примере, где pointer будет указывать на record если такое возможно. если уж совсем близко то на примере TServerSocket.Socket.Connections[0].Data).
← →
JanMihail © (2007-08-06 21:58) [1]type
MyRecord = record
str1: String[255];
str2: String[255];
i : Integer;
end;
var
Form1: TForm1;
a: MyRecord;
p: Pointer;
procedure TForm1.FormCreate(Sender: TObject);
begin
p := @a;
end;
← →
JanMihail © (2007-08-06 22:04) [2]Сам толком не поинмаю, что за Pointer
← →
Юрий Зотов © (2007-08-06 22:33) [3]Построение стека записей:
type
PData = ^TData; // Тип указателя на элемент стека
TData = record // Тип элемента стека
I: integer; // Данные элемента
S: string; // Еще данные элемента
Prev: PData; // Указатель на предыдущий элемент
end;
var
Last: PData = nil; // Указатель на верхний элемент стека (пока пустого).
proсedure Push; // Создать новый элемент и затолкнуть его в стек.
var
P: PData;
begin
New(P); // Создали в динамической памяти новый элемент по адресу P.
P^.Prev := Last; // Разместили новый элемент на вершине стека.
Last := P // Протолкнули стек.
end;
proсedure Pop; // Вытолкнуть из стека верхний элемент и уничтожить его.
var
P: PData;
begin
if Last = nil then // Если стек пустой, то ничего делать не надо.
Exit;
P := Last; // Запомнили адрес верхнего элемента.
Last := Last^.Prev; // Вытолкнули верхний элемент из стека.
Dispose(P); // Освободили память, которую он занимал.
end;
procedure Clear; // Очистить стек и освободить всю занимаемую им память.
begin
while Last <> nil do
Pop
end;
var
i: integer;
begin
// Создать стек из 10 элементов
for i := 0 to 9 do
begin
Push;
Last^.I := i;
Last^.S := "Элемент номер " + IntToStr(Last^.I);
end;
// Уничтожить стек
Clear
end;
← →
Салат (2007-08-06 22:48) [4]Спасибо, разобрался кое как :) вкривь и вкось сделал на массивах, но зато надежно, просто и работает. Для таких же как я может пригодится мой опыт:
TRecord = record
data: String[255];
end;
var
p: Pointer;
clients: array[0..2] of TRecord;
begin
p := @clients[1]; // связываем указатель с каким-то элементом массива
ShowMessage(TRecord(p^).data); // доступ к этому элементу
end;
← →
MetalFan © (2007-08-06 22:57) [5]хм... я раньше тоже не понимал) но однажды понял... но вот на пальцах объяснить не могу..
единственное, что в голову приходит: Pointer - это в общем случае просто 4 байта в памяти, "указывающие" на какую-либо область памяти или на nil...
к примеру:type
TRec = record
Int: Integer;
W: Word;
Str: string;
end;
procedure Proc;
var
lInt: Integer;
lStr: string;
lRec: TRec;
lPtr: Pointer;
begin
lInt := 10;
lPtr := @lInt;
Integer(lPtr^) := 20;//изменили значение lInt
lStr := "string";
lPtr := @lStr;
string(lPtr^) := "asd";// изменили значение lStr;
lRec.Int := 100;
lRec.W := 1;
lRec.Str := "sadssd";
lPtr := @lRec;
TRec(lPtr^).Int := 1;
TRec(lPtr^).W := 2;
TRec(lPtr^).Str := "nnn";
end;
← →
{RASkov} © (2007-08-06 22:57) [6]> [4] Салат (06.08.07 22:48)
В данном примере никакого смысла нет в указателях....
И вообще указатели лучше не использовать, если нет на то особой необходимости. См пример из [3]
type
PData = ^TData; // Тип указателя на элемент стека
TData = record // Тип элемента стека
I: integer; // Данные элемента
S: string; // Еще данные элемента
Prev: PData; // Указатель на предыдущий элемент <----------- Иначе никак, а то можно было б лучше так Prev: TData
end;
← →
Юрий Зотов © (2007-08-06 23:07) [7]> Салат (06.08.07 22:48) [4]
В Вашем варианте указатель вовсе не нужен:
ShowMessage(clients[1].data);
И без всяких указателей.
Вообще, указатель - это просто-напросто переменная, которая содержит в себе адрес, только и всего. Если значение указателя равно nil, то это значит, что он пустой (то есть, не содержит в себе никакого адреса). Ничего сложного.
← →
{RASkov} © (2007-08-06 23:07) [8]> [5] MetalFan © (06.08.07 22:57)
Собственно... тоже пример по работе с указателями, но не их необходимости :)
Мои посты может быть такие, из-за того, что я панически "боюсь" их(указатели) :) И без надобности их не трогою....
Кстати вопрос по ним, если можно задам здесь в тему.... вот из [3]Last^.S := "Элемент номер " + IntToStr(Last^.I);
Вот эти выделенные "крыши" - они непосредственно необходимы в данном месте или только для лучшего понимания, что есть что ??
Так какLast.S := "Элемент номер " + IntToStr(Last.I);
Результат тот же....
"Крыша" - разыменование указателя, это я знаю..... Делфи наверняка, если их(крыши) не ставить, сама их подставляет, так?
Вообщем с указателями только путаница :)
← →
MetalFan © (2007-08-06 23:24) [9]в случае с указателями на записи крышки можно и не ставить, среда и так поймет... но лучше, имхо, для наглядности все таки ставить ^
← →
Юрий Зотов © (2007-08-06 23:36) [10]> {RASkov} © (06.08.07 23:07) [8]
Да, компилятор Deplhi сам разыменовывает указатели. Любая объектная переменная ведь тоже указатель, поэтому по правилам Паскаля надо было бы писать, строго говоря, так:Button1^.Caption := "OK";
Но мы крышку не пишем, компилятор сам разыменовывает Button1.
Чтобы не путаться в своем же коде, я пользуюсь таким правилом: объектные переменные пусть разыменовывает компилятор, а простые (необъектные) указатели разыменовываю сам, по-старинке, явным образом. Это позволяет сразу отличать указатели от других типов переменных и правильно с ними работать (особенно, при использовании данных вида "указатель на указатель", когда требуется многократное разыменование).
> Вообщем с указателями только путаница
Никакой путаницы нет - надо только ОДИН раз понять, что это такое, а потом все будет очень просто. Указатели - штука для серьезного программиста совершенно необходимая (я бы даже сказал сильнее - кто не понимает указателей, того назвать программистом вообще нельзя). Без указателей нвозможно работать с динамической памятью напрямую (а это требуется частенько - например, при использовании многих функций WinAPI). Без понимания указателей нельзя толком понять и многие термины Delphi (длинная строка, динамический массив, объект, класс, VMT... и многое другое). Соответственно, не понимая этого, нельзя с этим и свободно работать - и именно от непонимания указателей бывает и много багов в программах, и много вопросов на форумах.
← →
Anatoly Podgoretsky © (2007-08-06 23:59) [11]> Юрий Зотов (06.08.2007 23:36:10) [10]
> Да, компилятор Deplhi сам разыменовывает указатели. Любая объектная переменная ведь
> тоже указатель, поэтому по правилам Паскаля надо было бы писать, строго говоря, так:
> Button1^.Caption := "OK";
> Но мы крышку не пишем, компилятор сам разыменовывает Button1.
Есть и исключение "Do not apply the dereference operator (^) to a dynamic-array variabl"
← →
{RASkov} © (2007-08-07 00:05) [12]> [10] Юрий Зотов © (06.08.07 23:36)
Спасибо.... есть польза.
Т.е. у типизированных указателей крышу ставить не обязательно, но желательно, а у не типизированных (Pointer) - обязательно.TMyRecord = record
str1 : String[255];
str2 : String[255];
i : Integer;
end;
PMyRecord = ^TMyRecord;
var
P: Pointer;
P1: PMyRecord;
.....
TMyRecord(P^).i:=5; - обязательна ^
P1^.i:=5; - ^ не обязательна
P1.i:=5;
> Никакой путаницы нет - надо только ОДИН раз понять
Самое обидное, это то, что я эти указатели, то понимаю, то нифика не понимаю... т.е. то они мне легко и просто даются, то как баран на них смотрю.
Другими словами можно конечно сказать, что я их не понимаю :(
Когда этих "крышек" нет то все ок, но когда они появляются, то вот здесь и бывают провалы...
Кстати.... пример в [3] довольно легко прочитался и понялся :) А в другом месте((примере), образно) могу запутаться :(
Ладно.... еще раз спасибо и сорри за оффтоп
← →
{RASkov} © (2007-08-07 00:26) [13]Вот опять запутался.... вы уж простите, что в чужой ветке, но автору тоже пойдет на пользу, так как его тоже интересует работа с указателями, а конкретного вопроса в топике не было...
Из соседней ветки:
Как все же правильнее, так:procedure TForm1.Button4Click(Sender: TObject);
const Clr: array [0..2] of TColor = (clRed, clBlue, clYellow);
begin
ListView1.Items[2].Data := @Clr[(Sender as TButton).Tag]; //@ - адрес локальной константы
ListView1.Invalidate;
end;
procedure TForm1.ListView1CustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
if Item.Data<>nil then ListView1.Canvas.Brush.Color := TColor(Item.Data^); //нужно разыминование, и почему этот адрес живой
end;
или так:procedure TForm1.Button4Click(Sender: TObject);
const Clr: array [0..2] of TColor = (clRed, clBlue, clYellow);
begin
ListView1.Items[2].Data := Pointer(Clr[(Sender as TButton).Tag]); //приводим к Pointer"у
ListView1.Invalidate;
end;
procedure TForm1.ListView1CustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
if Item.Data<>nil then ListView1.Canvas.Brush.Color := TColor(Item.Data); //Вроде нетипизированный указатель, а ^ не нужна
end;
или это одно и тоже? А то даю советы, а тут сам запутался :(
Оба примера рабочие.
Я так понимаю:
В первом примере- мы берем адрес локальной константы и пишем его в Data, а потом как этот локал адрес остается при разыменовании Data в другом месте? Повезло?
Во втором - ну здесь вроде более менее понятно... единственное только с крышкой не совсем понял...
Пора спать :)
← →
{RASkov} © (2007-08-07 00:38) [14]Второй пример разобрался...
Пишем вместо адреса - некое число (clRed, clBlue...)
И потом этот адрес(грубо - число) преобразуем к TColor и все нормально, поэтому нам "не страшно", что была локальная константа...
А вот в первом пишем адрес константы, а потом разыменовываем и преобразуем к TColor некий адрес констаны, и ... в общем непонятно...
Точно пора спать (
← →
Инс © (2007-08-07 00:43) [15]В первом случае мы в тэге сохраняем именно адрес. Потом, когда нужно получить значение цвета - разадресовываем. Во втором случае, мы сохраняем в тэге не адрес, а само значение, а приведение к Pointer делаем чтобы компилятор не ругался (так как свойство Data должно быть типа Pointer). Вот мы и заставляем компилятор думать, что TColor это Pointer. Раз в тэге НЕ адрес, то и разадресовывать не надо.
← →
Инс © (2007-08-07 00:47) [16]
> а потом разыменовываем и преобразуем к TColor некий адрес
> констаны
Уже не адрес приводим, а значение. Сначала разадресация (теперь у нас вместо адреса значение, только непонятно какого типа), а потом - приводим к типу TColor. Я бы лучше написал так, понятнее:
... := PColor(Item.Data)^;
← →
Юрий Зотов © (2007-08-07 00:53) [17]> {RASkov} © (07.08.07 00:26) [13]
В первом примере указатель живой потому, что компилятор разместил локальную константу в статической памяти. Ее адрес фиксирован и жив, пока жива сама программа.
Разыменование в первом примере нужно потому, что в Item.Data мы запоминали АДРЕС константы, а получить хотим ЗНАЧЕНИЕ этой константы. Во втором же примере в Item.Data мы запоминали не АДРЕС константы, а ее ЗНАЧЕНИЕ - поэтому разыменование не нужно.
Во втором примере использовался тот факт, что длина типов TColor и Pointer одинаковая (4 байта на 32-битных платформах), поэтому, если некая область (Item.Data) хранит некое число, то это число может быть и адресом, и цветом (да и вообще чем угодно: что мы туда положили - то там и будет). А чтобы компилятор не ругался на несоответствие типов, в коде второго примера дважды использовано явное приведение типа: при запоминании цвета в Item.Data тип TColor приводится к типу Pointer, а при чтении - наоборот.
← →
Инс © (2007-08-07 00:54) [18]
> [17] Юрий Зотов © (07.08.07 00:53)
Дуэтом :)
← →
{RASkov} © (2007-08-07 00:56) [19]Со вторым разобрался, а вот...
> В первом случае мы в тэге сохраняем именно адрес. Потом,
> когда нужно получить значение цвета - разадресовываем.
Мне все вроде понятно, будь глобальные объекты, но..... У локальных переменных, констант адреса остаються? Они(локальные пер/конст) вроде как при входе "инициализируються" при выходе освобождаются (память), .... как адрес на константу "живет" в другом методе....
Нет... я с указателями наверное крепко не подружусь :( Вроде все понятно, а с другой стороны...
> [16] Инс © (07.08.07 00:47)
Мне все понятно, но по отношению к глобальным вещам, а как это у локальных обстоит.... т.е. константа:
const Clr: array [0..2] of TColor = (clRed, clBlue, clYellow);
всегда в памяти присутствует?
← →
{RASkov} © (2007-08-07 00:57) [20]> [17] Юрий Зотов © (07.08.07 00:53)
> Ее адрес фиксирован и жив, пока жива сама программа.
Все встало на свои места.... Спасибо.
Все понятно теперь.... разобрался.
← →
Инс © (2007-08-07 00:59) [21]
> всегда в памяти присутствует?
Да, конечно. Понятие "локальная" для констант подразумевает только то, что вы не сможете к ней обратиться из-за пределов подпрограммы. Но константа на то и константа, ее значение нельзя изменить, и для этого компилятор располагает ее в в области памяти, защищенной от записи, но не в стеке.
← →
Инс © (2007-08-07 01:04) [22]Вы сами смогли бы это проверить. Адрес константы имеет значение, близкое к $00400000 - это адрес, по которому образ exe загружен в виртуальное АП. Из этого можно сделать вывод, что константа "вшита" в exe. Стек располагается совсем по другому адресу.
← →
{RASkov} © (2007-08-07 01:16) [23]> [21] Инс © (07.08.07 00:59)
Точно,
И вот доказательства:
Так не работает:procedure TForm1.Button4Click(Sender: TObject);
var Clr: array [0..2] of TColor;
begin
Clr[0]:=clRed; Clr[1]:=clBlue; Clr[2]:=clYellow;
ListView1.Items[2].Data:=@Clr[(Sender as TButton).Tag]; //пишем адрес локальной переменной
ListView1.Invalidate;
end;
if Item.Data<>nil then ListView1.Canvas.Brush.Color := TColor(Item.Data^); //пытаемся взять данные по "паленому" адресу
А так все ок:procedure TForm1.Button4Click(Sender: TObject);
var Clr: array [0..2] of TColor;
begin
Clr[0]:=clRed; Clr[1]:=clBlue; Clr[2]:=clYellow;
ListView1.Items[2].Data:=Pointer(Clr[(Sender as TButton).Tag]); //Вместо адреса на данные используем сам адрес в качестве значения цвета
ListView1.Invalidate;
end;
if Item.Data<>nil then ListView1.Canvas.Brush.Color := TColor(Item.Data); //Адрес Pointer используем в качестве цвета, И разыменование приведет к ошибке, так как данных по этому адресу нет....
> [22] Инс © (07.08.07 01:04)
> Адрес константы имеет значение, близкое к $00400000 - это
> адрес, по которому образ exe загружен в виртуальное АП
Я не настолько знаком с этим, но вот .... учусь потихоньку :) Надеюсь урок усвоил правильно. Спасибо.
← →
Германн © (2007-08-07 02:18) [24]
> {RASkov} © (07.08.07 01:16) [23]
>
> > [21] Инс © (07.08.07 00:59)
>
> Точно,
> И вот доказательства:
>
Из сего примера первый вывод, который нужно сделать - не стОит плодить лишние сущности! А переменнаяClr: array [0..2] of TColor
именно таковой и является. Не было б её, не было б и ошибок :)
← →
Салат (2007-08-07 07:09) [25]Кто думает что указатели в моем случае не нужны сильно заблуждаются :) В моем примере было все очень упрощено, на деле же нужно было связать ServerSocket.Socket.Connections[].Data (который Pointer) с некими данными которые идентифицировали бы этот сокет.
← →
{RASkov} © (2007-08-07 13:18) [26]> [25] Салат (07.08.07 07:09)
> Кто думает что указатели в моем случае не нужны сильно заблуждаются
И нечего здесь думать - не нужны они, тыж пример привел... [4]
> В моем примере было все очень упрощено
Ну так приведи другой пример.... наверняка они и там не нужны будут :)
К сожалению мне вот это:
> ServerSocket.Socket.Connections[].Data (который Pointer)
> с некими данными которые идентифицировали бы этот сокет.
... не о чем :(
> [24] Германн © (07.08.07 02:18)
Этот пример был только для доказательства, что адреса локальных констант сохраняються, а адреса переменных нет :)
А про указатели я свое мнение из [6] не поменяю.... пока, хоть и еще более ближе к ним(указателям) стал в этой ветке ;)
← →
Anatoly Podgoretsky © (2007-08-07 13:24) [27]> {RASkov} (07.08.2007 13:18:26) [26]
Менять не обязательно, а вот знания обязательно, иначе ущербность в знаниях.
← →
Сергей М. © (2007-08-07 13:31) [28]
> Салат (07.08.07 07:09) [25]
>
> Кто думает что указатели в моем случае не нужны сильно заблуждаются
Да что ты говоришь !?)
А мужики-то и не знают, что у тебя stNonBlocking)
← →
{RASkov} © (2007-08-07 13:34) [29]> [27] Anatoly Podgoretsky © (07.08.07 13:24)
Абсолютно согласен.... и поэтому не стесняюсь спрашивать, если что не понятно....
← →
MsGuns © (2007-08-07 16:45) [30]Указатели совершенно необходимы при работе со СПИСКАМИ однотипных сложных объектов (рекордов).
Страницы: 1 вся ветка
Форум: "Начинающим";
Текущий архив: 2007.09.02;
Скачать: [xml.tar.bz2];
Память: 0.55 MB
Время: 0.045 c