Модераторы: Snowy, MetalFan, bems, Poseidon
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> указатели. И какой от них толк? 
:(
    Опции темы
Teleport
Дата 13.12.2008, 14:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 557
Регистрация: 5.7.2008
Где: Прибалтика

Репутация: 1
Всего: 6



вот читаю об указателях. Прочитал кое что и понял, как их объявлять - эти указатели. Также понял, что 
"Используя указатели мы можем обращаться к любой ячейке в памяти и использовать размещённые там данные."

Вопрос1: идентичны ли строки:
Код

ptrString : PString;

и
Код

ptrString : ^String;


или же нужно использовать вот так:
Код

type
ptrString : ^String;
var
 ptrString : PString;



Вопрос 2: Зачем нужны указатели - вот не пойму никак. Везде описано - как объявить и как с ними операции проводить. Но не могу найти примера - где без указателей не обойтись или с указателями проще решить задачу чем без них.  Прошу привести простые примеры с пояснением.


--------------------
user posted image
user posted image 
PM MAIL   Вверх
Rrader
  Дата 13.12.2008, 16:06 (ссылка) |    (голосов:3) Загрузка ... Загрузка ... Быстрая цитата Цитата


Inspired =)
***


Профиль
Группа: Экс. модератор
Сообщений: 1535
Регистрация: 7.5.2005

Репутация: 18
Всего: 191



Указатели - вещь незаменимая во многих случаях. Позволю себе привести некоторые:

1) Адресная арифметика - позволяет увеличивать или уменьшать значение указателя на размер его типа, то есть позволяет "путешествовать" по памяти. Конечно, можно и не на размер типа увеличивать адрес в указателе, если указатель приводить к нужному типу при арифметических операциях. 

Классический пример - вычисление длины строки PAnsiChar. Строка оканчивается символом #0, а все символы расположены линейно по порядку - для подсчета длины можно просто инкрементировать указатель на текущий символ.

Код

function StringLength(P: PAnsiChar): Cardinal;
begin
  Result := 0;
  if P = NIL then Exit;
  while P^ <> #0 do
  begin
    Inc(Result);
    Inc(P);
  end;
end;


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

Удобно при работе с API. Допустим, в функцию передается целая структура, но параметр числовой. Как обработать? Тут помогают указатели. Рассмотрим жутко напаренный пример, но подобные вещи в API сплошь и рядом: обработка разнообразных сообщений, hook-процедур и т.д.)

Код

type
  PMyRecord = ^TMyRecord;
  TMyRecord = packed record
    FStringField: ShortString;
    FIntField: Integer;
  end;

....

procedure MyProc(Param: Integer);
begin
  with PMyRecord(Param)^ do
  begin
    ShowMessage(FStringField);
    ShowMessage(IntToStr(FIntField));
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Rec: TMyRecord;
begin
  Rec.FStringField := 'Text';
  Rec.FIntField := 10;
  MyProc(Integer(@Rec));
end;


В своей практике я очень часто использую адресную арифметику вместе с произвольным доступом, например, для путешествия по элементам таблиц Windows smile 

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

Код

type
  PMyArray = ^TMyArray;
  TMyArray = array[1..10000] of Integer;
...
procedure Proc1(Value: PMyArray);
var
  I :Integer;
begin
  for I := 1 to High(Value^) do
    Value^[I] := 1;
end;

procedure Proc2(Value: TMyArray);
var
  I: Integer;
begin
  for I := 1 to High(Value) do
    Value[I] := 1;
end;


Замерим их примерное быстродействие через GetThreadTimes.

Код

procedure TForm1.Button2Click(Sender: TObject);

 function FileTimeToQuadWord(FileTime: TFileTime): Int64;

    function Int64ShllMod32(Value: Int64; ShiftCount: DWORD) :Int64;
    begin
      Result := Value shl ShiftCount;
    end;

  begin
    Result := Int64ShllMod32(FileTime.dwHighDateTime, 32)
      or FileTime.dwLowDateTime;
  end;

var
  ftKernelTimeStart, ftKernelTimeEnd: TFileTime;
  ftUserTimeStart, ftUserTimeEnd: TFileTime;
  ftDummy: TFileTime;
  qwKernelTimeElapsed1, qwUserTimeElapsed1, qwTotalTimeElapsed1: Int64;
  qwKernelTimeElapsed2, qwUserTimeElapsed2, qwTotalTimeElapsed2: Int64;
  I: Integer;
  Arr: TMyArray;
begin
  { Часть 1 }
  GetThreadTimes(GetCurrentThread, ftDummy, ftDummy,
    ftKernelTimeStart, ftUserTimeStart);

  // Начало кода
  for I := 0 to 100000 do
    { Принимает указатель }
    Proc1(@Arr);
  // Конец кода

  GetThreadTimes(GetCurrentThread, ftDummy, ftDummy,
    ftKernelTimeEnd, ftUserTimeEnd);
  qwKernelTimeElapsed1 := FileTimeToQuadWord(ftKernelTimeEnd) -
    FileTimeToQuadWord(ftKernelTimeStart);
  qwUserTimeElapsed1 := FileTimeToQuadWord(ftUserTimeEnd) -
    FileTimeToQuadWord(ftUserTimeStart);
  qwTotalTimeElapsed1 := qwKernelTimeElapsed1 + qwUserTimeElapsed1;
  { Часть 2 }
  GetThreadTimes(GetCurrentThread, ftDummy, ftDummy,
    ftKernelTimeStart, ftUserTimeStart);

  // Начало кода
  for I := 0 to 100000 do
    { Принимает массив }
    Proc2(Arr);
  // Конец кода

  GetThreadTimes(GetCurrentThread, ftDummy, ftDummy,
    ftKernelTimeEnd, ftUserTimeEnd);
  qwKernelTimeElapsed2 := FileTimeToQuadWord(ftKernelTimeEnd) -
    FileTimeToQuadWord(ftKernelTimeStart);
  qwUserTimeElapsed2 := FileTimeToQuadWord(ftUserTimeEnd) -
    FileTimeToQuadWord(ftUserTimeStart);
  qwTotalTimeElapsed2 := qwKernelTimeElapsed2 + qwUserTimeElapsed2;
  { Результат }
  ShowMessage(IntToStr(Round((qwTotalTimeElapsed2 - qwTotalTimeElapsed1) /
    qwTotalTimeElapsed2 * 100)) + '%');
end;


У меня разница в быстродействии примерно 40%, то есть функция, принимающая указатель, работает быстрее. Подумай сам, почему так происходит smile 

4) Добавлю еще один классический пример, где без указателей не обойтись smile 

Допустим, нужно создать односвязный список через массив записей (10 элементов). В каждой записи ровно два поля - указатель на следующий элемент списка и данные (пусть у нас это целое число). Односвязный список подразумевает, что мы можем проходить его только в одном направлении. Следующее объявление некорректно:
Код

type
  TOneWayListItem = record
    { Следующий элемент }
    FNextItem: TOneWayListItem;
    { Данные }
    FData: Integer;
  end;

  TOneWayList = array[1..10] of TOneWayListItem;

Цитата

[DCC Error] Unit1.pas(19): E2086 Type 'TOneWayListItem' is not yet completely defined

Решить проблему можно с помощью указателей. Дефинировать (объявлять) их можно до дефиниции самого типа. Вот рабочий вариант:
Код

type
  POneWayListItem = ^TOneWayListItem;
  TOneWayListItem = record
    { Следующий элемент }
    FNextItem: POneWayListItem;
    { Данные }
    FData: Integer;
  end;

  TOneWayList = array[1..10] of TOneWayListItem;

С таким списком нужно работать, самостоятельно выделяя и освобожая память.

Это сообщение отредактировал(а) Rrader - 17.12.2008, 05:17


--------------------
Let's do this quickly!
Rest in peace, Vit!
PM MAIL Skype   Вверх
Teleport
Дата 13.12.2008, 17:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 557
Регистрация: 5.7.2008
Где: Прибалтика

Репутация: 1
Всего: 6



более менее понял только первые 2 примера.. smile спасибо smile


--------------------
user posted image
user posted image 
PM MAIL   Вверх
NewDima
Дата 15.12.2008, 05:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 922
Регистрация: 20.2.2006
Где: <?here?>

Репутация: нет
Всего: 12



так же не обойтись без указателей при создании графов. Закономерные структуры вообще хранятся в динамических структурах, а без указателей здесь не обойтись.
и, кстати,
Код

type
ptrString = ^string;

 smile 
PM ICQ   Вверх
Christoph
Дата 15.12.2008, 18:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 667
Регистрация: 23.1.2008
Где: Харьков

Репутация: 5
Всего: 11



А что если напишу без type? то не будет работать?  smile 


--------------------
user posted image
PM MAIL ICQ   Вверх
NewDima
Дата 15.12.2008, 18:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 922
Регистрация: 20.2.2006
Где: <?here?>

Репутация: нет
Всего: 12



я про знак "="
PM ICQ   Вверх
Teleport
Дата 15.12.2008, 21:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 557
Регистрация: 5.7.2008
Где: Прибалтика

Репутация: 1
Всего: 6



точно, знак равно smile Спасибо smile


--------------------
user posted image
user posted image 
PM MAIL   Вверх
ama_kid
Дата 16.12.2008, 15:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


АСУТП-кодер
***


Профиль
Группа: Комодератор
Сообщений: 1460
Регистрация: 5.3.2007
Где: Москва

Репутация: 9
Всего: 95



Цитата(Teleport @  13.12.2008,  15:57 Найти цитируемый пост)
Но не могу найти примера - где без указателей не обойтись
попробуй без указателя сменить главную форму приложения Delphi в рантайме  smile 
Код
procedure TForm1.Button1Click(Sender: TObject);
var
 pMain:pointer;
begin
 pMain:[email protected];
 TForm(pMain^):=Form2;
end;




--------------------
самурай без меча подобен самураю с мечом, но только без меча 
PM MAIL   Вверх
bems
Дата 16.12.2008, 21:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 18
Всего: 88



ama_kid, грязный хак. А если в следующей версии для чтения этого свойства будет использоваться функция, а не поле? (имеют право, это внутренние дела класса)


--------------------
Обижено школьников: 8
PM MAIL   Вверх
ama_kid
Дата 16.12.2008, 23:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


АСУТП-кодер
***


Профиль
Группа: Комодератор
Сообщений: 1460
Регистрация: 5.3.2007
Где: Москва

Репутация: 9
Всего: 95



Цитата(bems @  16.12.2008,  22:36 Найти цитируемый пост)
грязный хак
не спорю, но суть вопроса-ответа не в этом smile
Цитата(bems @  16.12.2008,  22:36 Найти цитируемый пост)
А если в следующей версии для чтения этого свойства будет использоваться функция, а не поле?
Имеют право, да, но в этом случае с тем же успехом можно воспользоваться ассемблером и знанием смещения адреса приватной переменной от начала класса... Но, напоминаю, вопрос-то был в другом...

Добавлено через 2 минуты и 24 секунды
я лишь привел пример, прямо иллюстрирующий полезность указателей в ответ на изначальный вопрос... 


--------------------
самурай без меча подобен самураю с мечом, но только без меча 
PM MAIL   Вверх
Bose
Дата 17.12.2008, 03:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1458
Регистрация: 5.3.2005
Где: Riga, Latvia

Репутация: 8
Всего: 51



Без указателей вообще никак. Любая переменная объектного типа по сути является указателем.
PM MAIL WWW Skype   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Для новичков"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0536 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.