Home > Articles

0672320606

Pointers

Pascal pointers are just like C or C++ pointers: They are the key to what makes the language so powerful, but they can also cause you considerable pain.

I'll start by showing you what the untamed pointer type looks like in Object Pascal. Most people won't want to use pointers this way, but I think it helps to start by seeing the low-level usage. Then I'll show you the somewhat more civilized way pointers most often appear in Kylix programs. This is the undomesticated version:

procedure TForm1.Button1Click(Sender: TObject);
var
  P: Pointer;
  S, Temp: String;
begin
  S := `Sam';                // Set S = `Sam'
  GetMem(P, 10);             // Allocate 10 bytes
  FillChar(P^, 10, 0);       // Zero out all 10 bytes
  Move(S[1], P^, Length(S)); // Move `Sam' into P^
  SetLength(Temp, 4);        // Make Temp four bytes long
  Move(P^, Temp[1], 1);      // Move S from P to temp
  Inc(PChar(P));             // Make P point to am
  Move(P^, Temp[2], 1);      // Move a from P to temp
  Inc(PChar(P));             // Make P point to m
  Move(P^, Temp[3], 1);      // Move m from P to temp
  Temp[4] := #0;             // Set the null terminator for temp
  Dec(PChar(P), 2);          // Make P point at Sam
  FreeMem(P, 10);            // Free memory allocated for Sam
  Edit1.Text := Temp;
end;

This code is from a program named Pointers, which is in the Chap03 directory on your accompanying CD. The Button1Click method shown here does nothing practical other than show how to use pointer syntax in Object Pascal. In particular, the code creates a pointer of 10 bytes of memory. It zeroes out the bytes that the pointer addresses. Then it copies a string into the bytes address by the pointer. Finally, it accesses the contents of pointer, 1 byte at a time.

The Pascal pointer type is, logically enough, referred to as a pointer. Use the ^ operator operator>to address the memory associated with a pointer. The ^ operator performs more or less the same function in Pascal as the -> operator does in C and C++.

I have commented this code so heavily that you can probably best follow it by simply reading the code itself. Notice, in particular, the following calls:

  • The GetMem procedure allocates memory for a pointer. Pass the pointer in the first parameter and the number of bytes that you want to allocate in the second parameter. You will receive a copy of a fully initialized pointer to the amount of memory that you requested.

  • FillChar can be used to spray a single-character value into multiple contiguous bytes in a very efficient manner. Commonly, it is used to zero out the bytes in a contiguous chunk of memory. In this case, I tell FillChar to fill the 10 bytes pointed to by P with the value 0. This is the first character in the character set, not the number 0. The first parameter of the function specifies the memory that you want to fill, the second specifies the number of bytes of that memory that you want to address, and the third parameter is the character that you want to spray into those bytes. Needless to say, the routine is designed to be very fast.

  • The Move procedure moves n number of bytes from one place in memory to another place. In this case, I move the 3 bytes addressed by the String variable into the bytes address by the pointer. The first parameter of the Move procedure is the source memory, the second is the destination memory, and the third is the number of bytes to be moved.

  • Notice that I use the Inc and Dec procedures to iterate over particular bytes in the memory addressed by the pointer. This technique is known as pointer arithmetic, and it should be familiar to all C or C++ programmers. You will get a more detailed look at pointer arithmetic in Chapter 5, in the sections on the debugger. After the call to Move, the pointer points at the letters S, a, and m. The last 7 bytes addressed by the pointer are still zeroed out. If I call Inc(P) one time, then the first byte addressed by the pointer is no longer S, but a. In C or C++, you would achieve the same effect by writing P++.

  • The FreeMem procedure deallocates the memory assigned to the pointer P. Notice that I use Dec to unwind the memory addressed by the variable P back to the place initially allocated by the call to get GetMem. Failure to do this can yield undefined results.

The best way to understand these lines of code is to watch them very carefully in the debugger. Unfortunately, I have not yet talked to you about using the debugger. Furthermore, the parts of the debugger that you can use to really get a look at this code are relatively advanced features. As a result, I'm going to have to ask you to put this code aside for a time. Then, in Chapter 5, in the section "Using the Debugger," I will show you how to get a good look at what happens under the hood when this code is executed.

Working with Pointers to Objects

The type of pointer that I showed you in the last section is really an advanced technique, not one that you are likely to employ in many sections of your code. Pointers to objects, however, are ubiquitous in Object Pascal, and you must understand them if you want to work with Kylix.

NOTE

In this section and the next, I talk a good deal about how objects work in Kylix. I assume that all readers of this book already understand objects as well as polymorphism, inheritance, encapsulation, virtual methods, and related topics. My goal in this text is not to explain OOP in and of itself, but instead to introduce or reintroduce Pascal objects to experienced programmers from other languages such as C++, VB, and Java.

Like Strings, pointers have a rather checkered history in Object Pascal. For many years, a Pascal pointer was a Pascal pointer, and as long as you understood how memory is addressed by a computer, they were fairly simple to use. In recent years, however, the waters have been muddied to make some changes that make programming easier for certain types of developers.

For many years, the basic rule for pointers was that if you wanted to address the memory they referenced, you used pointer syntax. For instance, you wrote MyPointer^.SomeBlockOfMemory. Spoken out loud, this is usually rendered as, "MyPointer points to SomeBlockOfMemory." This syntax is easy for intermediate and advanced-level programmers to use. However, inexperienced programmers can find it disconcerting. To solve their feelings, the Pascal team decided to drop the ^ operator. The result is simple dot notation: MyPointer.SomeBlockOfMemory. When working with Pascal objects, you can now leave off the ^.

Note, in particular, that all CLX objects should be addressed using dot notation. No one writes TEdit^.Text; they all write TEdit.Text.

You and I know, however, that this dropping of the pointer syntax is a simple affectation. It is a euphemism. Underneath this thin veneer, the untamed beast sharpens its claws on the bark of exotic tropical trees, its lidded eyes never still, its body crouching as it waits for you to make a false move. At this point it will—well, I'm not allowed to talk about that kind of thing in a book intended for general audiences. But if you have ever used a Microsoft product or attended a Bill Gate's demo, or if you have had a glimpse of the dreaded blue screen of death, then I'm sure you know something of what can happen.

NOTE

When they dropped the pointer syntax for objects, the Delphi and Kylix engineers also decided to place a T rather than a P before the declarations for these objects. For instance, it is proper to write TEdit or TButton, but not PEdit or PButton. Normally, you would put a P rather than a T before a pointer type. However, the game is properly afoot, and to play along you should use a T rather than a P.

The biggest issue when you use pointers is to make sure that the pointer is allocated properly and, even more importantly, that it is disposed of properly. In Kylix, these chores are largely taken out of the users' hands by two mechanisms:

  1. In design mode, when you drop a component onto a form or onto another component, memory for that component is allocated automatically.

  2. When a form closes, it automatically disposes of the memory associated with all the components that it owns. In fact, when any component that owns another component is destroyed, that component frees the memory for all the components that it owns. (In the section "Arrays", you saw the Component array that belongs to a form. We used that array for our purposes, but its primary purpose is to allow the form to track the components that it owns and to dispose of them properly when the time comes.)

Now you can begin to understand what the designers of Pascal have done:

  • They've made Pascal allocate memory for you automatically most of the time when you're working in the Form Designer.

  • When the time comes, Pascal will automatically dispose of the components.

  • They've unburdened developers of the need to use the ^ syntax.

If you put these three pieces together, you can see that Delphi goes a long way toward entirely relieving you of the duty to think about pointers or to even know that pointers are being used.

All of that is well and good—except for one crucial fact: Object Pascal uses pointers everywhere! Every component that you drop on a form is a pointer to an object. In fact, it is not possible to create a static instance of an object in Pascal. All Pascal components must be created as pointers to components. Indeed, all Pascal objects must be instantiated as pointers!

Listing 3.5 shows how to explicitly create an instance of an object. This is information that you must understand for those times when you create objects on your own rather than by dropping them onto the Component Palette:

Listing 3.5  A Short Console Application Found on Disk as ObjectAllocate1.dpr

program ObjectAllocateOne;

{$APPTYPE CONSOLE}
uses SysUtils;

type
  TMyObject = class(TObject)
    procedure SayYourName;
  end;

{ MyObject }

procedure TMyObject.SayYourName;
begin
  WriteLn(ClassName);
end;

var
  MyObject: TMyObject;
begin
  MyObject := TMyObject.Create;
  MyObject.SayYourName;
  MyObject.Free;
end.

This program is a console application. You can create console applications by choosing File, New, Console Application from the menu system. Console applications are not run as part of X. Instead, they are run from the shell prompt and usually output only raw text.

NOTE

It is traditional to end console applications with the ReadLn statement while you are debugging them in the IDE. This ensures that the window that the program creates stays open until you press the Enter key. If you start Kylix from the shell prompt, there is no reason to use this mechanism. Instead, the text from your program will be seen at the shell prompt from which you started Kylix. (In fact, it might be the case in the first version of Kylix that this latter mechanism is the only way to see the output from your console applications.) Remember that when you start Kylix from the shell prompt, you should use the command startkylix.

The ObjectAllocateOne program declares a simple Object Pascal class named TMyObject. With rare exceptions, all Object Pascal classes should begin with T, which stands for "type." To declare the class, you write TMyObject = class(TObject), where TObject is the name of the parent class.

To create an instance of TMyObject, you write the following code:

var
  MyObject: TMyObject;
begin
  MyObject := TMyObject.Create;
  ... // Code omitted here

This code allocates memory for an object. Java and C++ programmers would achieve the same ends by writing MyObject = new TMyObject(). VB programmers would write Dim MyObject as TMyObject. But parallels with VB and Java are inappropriate because Pascal treats pointers the same way C++ does. If you allocate memory for an object, you must free that memory or risk crippling your program!

Here is how to free memory for a Pascal object:

  MyObject.Free;

This code destroys the memory associated with TMyObject. After you have made this call, you can no longer safely reference MyObject.

Pointers, Constructors, and Destructors

When you call Free on an object, the compiler also calls the destructor for your object, if there is one. The ObjectAllocateTwo program, shown in Listing 3.6, demonstrates how this works.

Listing 3.6  The ObjectAllocateTwo Program, Featuring a Constructor That Allocates Memory and a Destructor That Destroys That Same Memory

program ObjectAllocateTwo;
{$APPTYPE CONSOLE}
uses
  SysUtils;

type
  TMyObject = class(TObject)
  private
    FMyPointer: Pointer;
  protected
    constructor Create; virtual;
    destructor Destroy; override;
  public
    procedure SayYourName;
  end;

{ MyObject }

constructor TMyObject.Create;
begin
  inherited Create;
  GetMem(FMyPointer, 10);
end;

destructor TMyObject.Destroy;
begin
  FreeMem(FMyPointer, 10);
  inherited;
end;

procedure TMyObject.SayYourName;
begin
  WriteLn(ClassName);
end;

var
  MyObject: TMyObject;
begin
  MyObject := TMyObject.Create;
  MyObject.SayYourName;
  FreeAndNil(MyObject);
end.

Many programs contain pointers that need to be allocated and deallocated. When allocating memory for an object that will belong to another object, you should do one of two things:

  • Declare the pointer or object as a method-scoped variable, and then allocate and deallocate the memory for that object inside one single method. This is the way the variable P is treated in the Button1Click method from the earlier section of this chapter titled "Pointers." In that method, P belongs to the Button1Click method, and the Button1Click method therefore takes on the chore of both allocating and deallocating memory for that object.

  • The second method is shown in the AllocateObjectTwo program. In that program, the variable FMyPointer is declared as a field of TMyObject. (The name of all fields of Pascal objects should begin with F, which stands for "field.") The memory for FMyPointer is allocated in the object's constructor and deallocated in the object's destructor. If you do things in this way, you are unlikely to forget to either allocate or deallocate memory for your object. In particular, all you need do is see what pointers or objects are declared as fields of your object and then make sure that they are allocated in the constructor and deallocated in the destructor. If you have declared five fields for your object but only four of those fields are cleaned up in your destructor, you likely have a problem.

There is nothing in Object Pascal to keep you from allocating and deallocating memory for your objects and pointers wherever you please. These rules are merely guidelines. In some cases, it will not be possible to follow these guidelines, but you should heed them if you can.

virtual Methods and the override Directive

In the AllocateObjectTwo program, the directive virtual is placed after the constructor for TmyObject, and the directive override follows the destructor. The first time you declare a method that you want to be virtual, use the directive virtual. If you are overriding an already existing virtual method, use the directive override.

All Pascal objects are guaranteed to have a destructor named Destroy and a method named Free. The purpose of the Free method is to call the destructor. More particularly, the Free method ensures that the object is not already set to nil; if it is not, the method calls Destroy.

Pascal objects inherit the Free and Destroy methods from TObject. When it comes time for a component to deallocate the memory for all the components that it owns, it simply calls TObject.Free on all the objects in its Components array. Through the miracle of polymorphism, this single call ensures that the destructors for each object are called. The end result is that all the memory for these objects is destroyed. This mechanism will not work, however, unless you override the Destroy method in your programs whenever you need to deallocate the memory associated with any of the fields of your object.

There is no need to override Destroy in the AllocateObjectOne program because the instance of TMyObject in that program does not have any fields for which it allocates memory. This is not the case in the AllocateObjectTwo program, so it is necessary to create a destructor for that object. Note further that in the AllocateObjectTwo program, TMyObject is not owned by a component. As a result, you must specifically call its destructor, as shown in that program. If TMyObject were owned by a component, you would not need to explicitly call Free on that object because its owner would perform the task for you.

NOTE

Newcomers to Object Pascal likely will have further questions at this point about the difference between objects and components. In general, a component is simply an object that you can place on the Component Palette. Saying as much, however, raises as many questions as it answers. Part II is dedicated to components, and there you will learn about them in depth.

I've tried to cover most of the major subjects about pointers that I think can cause confusion. If you want to hear more about pointers to objects, don't worry—the subject will come up again in Part II, when the focus of the text becomes CLX.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020