Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 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.089 c
4-1173165948
vir
2007-03-06 10:25
2007.09.02
Получить хенл окна имеющего фокус.


2-1186468272
gentos
2007-08-07 10:31
2007.09.02
как в TdxDBGrid делать кнопку с тремя точками в колонке ?


3-1178790763
Godness
2007-05-10 13:52
2007.09.02
A query with LOB s requires OCI8 mode, but OCI7 mode is used


15-1185970305
max999
2007-08-01 16:11
2007.09.02
как удалить файл?


2-1186485158
Надежда
2007-08-07 15:12
2007.09.02
Проверка не запущена ли уже эта программа





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский