Pointers In Delphi

Every data we use in an application is stored somewhere in the computer's memory. And a Pointer is a variable that stores a address of memory piece 
where we store data, like in Delphi "a string is really just a pointer" or "an object is really just a pointer" or "event handler such as OnClick is actually a pointer to a procedure". They allow direct access to memory, enabling complex data structures to be built and navigated.

The advantages are:
  • We can set that memory size as per our requirement
  • In case of copy value of a variable from one to another we just need to change a pointer to point to a different address of memory which saved lots of time
When we use Pointers
The most common use for pointers in Delphi is when calling Windows APIs. Windows API functions use a number of data types that may be unfamiliar to the Delphi programmer. Most of the parameters in calling API functions are pointers to some data type. 

Most of the time pointers in Delphi point to a specific type:
Example...
var
 iValue, j : integer;
 pIntValue : ^integer;
begin
  iValue := 2001;
  pIntValue := @iValue;
  ...
  j:= pIntValue^;
end;
caret (^) operator
In the above code to declare a pointer data type we use a caret (^). iValue is an integer type variable and pIntValue is an integer type pointer.

@ operator or ADDR function
Since a pointer is nothing more than an address in memory, we must assign to it the address of value stored in iValue integer variable. So we use @ operator which returns the address of a variable or a function or procedure.

Note that pIntValue's value is not 2001. In the code above the pIntValue is a typed integer pointer. And when "^" appears after a pointer variable, it dereferences the pointer and returns the value stored at the memory address held by the pointer. In the code above variable j has the same value as iValue.

Initializing pointers with NIL value
Unassigned pointers are dangerous. Since pointers let us work directly with computer's memory, if we try to write to a protected location in memory we could get a access violation error. This is the reason why we should always initialize a pointer to NIL. NIL is a special constant that can be assigned to any pointer. When NIL is assigned to a pointer, the pointer doesn’t reference anything.
Example...
var
  iTest1 : ^Integer;   // A pointer to a integer value
begin
  iTest1 := Nil;
end;

Pointer Data Type in Delphi 
The Pointer type provides a general use pointer to any memory based variable.
Example...
var
  generalPtr : Pointer;  // A pointer to anything
  formPtr    : ^TForm;   // A pointer to a form object
begin
  // The current unit's form is addressable via the self keyword
  generalPtr := Addr(self);

  // We can assign this pointer to the form pointer
  formPtr := generalPtr;

  // And set the form caption to show this
  formPtr.Caption := 'Test Pointer type';
end;

PChar in Delphi
The generic PChar represents a pointer to a Char variable. These character pointers are used to manipulate null-terminated strings. So PChar as being a pointer to a null-terminated string or to the array of string. 
Example...
var
   myString  : string;
   myCharPtr : PChar;
   i : Integer; 
 begin
   // Create a string of Char's
   myString  := 'Hello World';
 
   // Point to the first character in the string
   i := 1;
   myCharPtr := Addr(myString[i]);
 
   // Display all characters in the string
   while i <= Length(myString) do
   begin
     ShowMessage(myCharPtr^);  // Display the string characters one by one
     Inc(i);
     Inc(myCharPtr);
   end;
 end;

Other Typed pointers in Delphi
PAnsiChar A Pointer to an AnsiChar value
PAnsiString A Pointer to an AnsiString value
PChar A Pointer to an Char value
PCurrency A Pointer to a Currency value
PDateTime  A Pointer to a TDateTime value
PExtended A Pointer to a Extended floating point value
PInt64 A Pointer to an Int64 value
PShortString A pointer to an ShortString value
PString A Pointer to a String value
PVariant A Pointer to a Variant value
PWideChar        A Pointer to a WideChar
PWideString A Pointer to a WideString value

Record pointers
We can declare a Pointer for Records(Structures in C) declared in Delphi.
Example...
 type
   TMyRecord = Record
     name : String[20];
     age  : Integer;
 end;
 
 var
   myRecord    : TMyRecord;
   myRecordPtr : ^TMyRecord;
 begin
   myRecord.name := 'james';
   myRecord.age  := 20;
 
   myRecordPtr := @myRecord;
 
   ShowMessage(myRecordptr.name);  // Displays 'james'
 end;

Procedural and Method Pointers
Another important Pointer concept in Delphi are procedure and method pointers. Pointers that point to the address of a procedure or function are called procedural pointers. Method pointers are similar to procedure pointers. However, instead of pointing to stand-alone procedures, they must point to class methods. Method pointer is a pointer that contains information about the name of the method that is being invoked as well as the object that is being invoked and mostly used for component Events like onClick, calling DLL functions.
Example...
type
  TFunctionPtr = function (P1: integer) : string;

function MyFunction(P1: integer): string;
begin
  result := IntToStr(P1);
end;

procedure Caller(Func: TFunctionPtr; Version: integer);
begin
  Writeln('My current Delphi version = ' + Func(Version));
end;

begin
  Caller(@MyFunction, 10);
  Readln;
end.

Pointer and Memory Allocation (GetMem / FreeMem)
The real power of pointers comes from the ability to set aside memory while the program is executing. Pointers are variables like any variable, they should be initialized, either by assigning another pointer value to them, or by using New or GetMem and free them using FreeMem. The following code is used to change the text (caption) of the control with the Handle provided.
Example...
procedure GetTextFromHandle(hWND: THandle) ;
 var 
    pText : PChar; //a pointer to char (see above)
    TextLen : integer;
begin
 {get the length of the text}
 TextLen:=GetWindowTextLength(hWND) ;

 {alocate memory}
 GetMem(pText,TextLen) ; // takes a pointer

 {get the control's text}
 GetWindowText(hWND, pText, TextLen + 1) ;

 {display the text}
 ShowMessage(String(pText))

 {free the memory}
 FreeMem(pText) ;
end;

Points need to care when we use Pointers in application
If Pointer used properly, then they are very useful and flexible. But if you make a mistake, they can be a big problem that's why many people avoid pointers 
as much as they can. Some of the most common errors are...
- Uninitialized pointers
- Invalid type
- Type cast

Comments

Popular posts from this blog

MS Excel Automation in Delphi

ShellExecute in Delphi

Drawing Shapes in Delphi