Originale-mail to me for new edition

 

Overview of pointers

 

To see how pointers work, look at the following example.

1    var

2      X, Y: Integer;   // X and Y are Integer variables

3      P: ^Integer;     // P points to an Integer

4    begin

5      X := 17;         // assign a value to X

6      P := @X;         // assign the address of X to P

7      Y := P^;         // dereference P; assign the result to Y

8    end;

Line 2 declares X and Y as variables of type Integer. Line 3 declares P as a pointer to an Integer value; this means that P can point to the location of X or Y. Line 5 assigns a value to X, and line 6 assigns the address of X (denoted by @X) to P. Finally, line 7 retrieves the value at the location pointed to by P (denoted by ^P) and assigns it to Y. After this code executes, X and Y have the same value, namely 17.

The @ operator, which we have used here to take the address of a variable, also operates on functions and procedures. For more information, see The @ operator and Procedural types in statements and expressions.

The symbol ^ has two purposes, both of which are illustrated in our example. When it appears before a type identifier

^typeName

it denotes a type that represents pointers to variables of type typeName. When it appears after a pointer variable

pointer^

it dereferences the pointer; that is, it returns the value stored at the memory address held by the pointer.

Our example may seem like a roundabout way of copying the value of one variable to another something that we could have accomplished with a simple assignment statement. But pointers are useful for several reasons. First, understanding pointers will help you to understand Object Pascal, since pointers often operate behind the scenes in code where they don’t appear explicitly. Any data type that requires large, dynamically allocated blocks of memory uses pointers. Long-string variables, for instance, are implicitly pointers, as are class variables. Moreover, some advanced programming techniques require the use of pointers.

Finally, pointers are sometimes the only way to circumvent Object Pascal’s strict data typing. By referencing a variable with an all-purpose Pointer, casting the Pointer to a more specific type, and then dereferencing it, you can treat the data stored by any variable as if it belonged to any type. For example, the following code assigns data stored in a real variable to an integer variable.

type

  PInteger = ^Integer;

var

  R: Single;

  I: Integer;

  P: Pointer;

  PI: PInteger;

begin

  ...

  P := @R;

  PI := PInteger(P);

  I := PI^;

end;

Of course, reals and integers are stored in different formats. This assignment simply copies raw binary data from R to I, without converting it.

In addition to assigning the result of an @ operation, you can use several standard routines to give a value to a pointer. The New and GetMem procedures assign a memory address to an existing pointer, while the Addr and Ptr functions return a pointer to a specified address or variable.

Dereferenced pointers can be qualified and can function as qualifiers, as in the expression P1^.Data^.

The reserved word 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.

 

Topic groups

 

See also

About pointer types

Pointer operators

Pointers and pointer types

The @ operator

 

 

译文

 

指针:概述

 

首先看下面的范例中指针是如何工作的:

1    var

2      X, Y: Integer;   // XY是整数类型的变量

3      P: ^Integer;     // P是指向一个整数的指针

4    begin

5      X := 17;         // X赋值

6      P := @X;         // X的地址赋给P

7      Y := P^;         // 对指针P解除参照,将结果赋给Y

8    end;

2行声明了Integer类型的变量XY。第3行声明了指向Integer值的指针P,意味着指针P可以指向变量XY的位置。第5行向X赋值,第6行把X的地址(表示为@X)赋给指针P。最后,第7行重新找回指针P所指的位置的值(表示为P^,原文显然有误:^P)并赋给Y。这些代码执行后,XY具有相同的值,即17

在这里用于获得变量地址的地址运算符(@),也可以作用于函数和过程。更多信息见地址(@)运算符语句和表达式中的程序型类型

符号 ^ 有两种用途,在本例中都说明了。当它出现在类型标识符之前,如

^typeName

表示一个类型,该类型表示指向typeName类型变量的指针。当它出现在指针变量之后,如

pointer^

该符号对指针解除参照,也就是说,返回存储在内存地址(该地址保存在指针中)的值。

上面的例子看起来好象为了复制一个整数值绕了不少弯路,因为完全可以直接用简单的赋值语句达到相同目的。(这里为了说明指针的基本用法,的确是这样。)但是,指针的确有用。首先,理解指针有助于理解Object Pascal,因为指针常常在其没有直接出现的地方在后台代码中操作。所有需要大容量或动态分配的内存快都使用了指针。例如,长串变量就是隐式指针,类变量也是。此外,一些高级编程技术也需要使用指针。

最后,指针有时是超越Object Pascal精确数据分类的唯一途径。用可以指向所有数据类型的一般指针Pointer引用一个变量,将其转换成为一个更特殊的类型,然后对其接触参照,这是可以把存储在任意变量中的数据视为属于任意类型。例如,下面的代码将保存在实数变量中的数据赋给了整数变量(不是数字值的复制),

type

  PInteger = ^Integer;

var

  R: Single;

  I: Integer;

  P: Pointer;

  PI: PInteger;

begin

  ...

  P := @R;

  PI := PInteger(P);

  I := PI^;

end;

当然,实数和整数的存储格式不同。这里的赋值只是简单地将R中的二进制数据复制到I中,而没有做任何变换。

除了将地址运算符(@)的操作结果赋给指针以外,还可以使用几个标准例程把变量传递给指针。NewGetMem过程可以将内存地址赋给存在的指针;另外,AddrPtr函数向指定的地址或变量返回一个指针。

解除参照的指针可以被限定词限定,也可以作为限定词,如表达式P1^.Data^

保留字nil是一个特殊的常量,可以被赋值到任何指针。当nil被赋给一个指针时,指针不能引用任何实体。

 

主题组

 

相关主题

关于指针类型

指针运算符

指针和指针类型

地址(@)运算符

 

 

编者注

 

标准函数AddrPtr的一般用法可以参考如下代码:

 

{Addr的用法示例:}

var

  X: Integer;

  P: ^Integer;

begin

  X := 123;

  P := Addr(X);//等价于 P := @X;

  P^ := 234;//执行后X的值为234

  ...

end;

 

{Ptr的用法示例:}

var

  X: Integer;

  P, Q: ^Integer;

  A: Integer;

begin

  X := 123;

  P := Addr(X);

  A := Integer(P);//将指针转换为用整数类型表示的地址

  Q := Ptr(A);

  Q^ := 234;//执行后X的值为234

  ...

end;

 

可以看出,Addr函数等价于地址运算符(@),该函数接受任何有效标识符,包括变量、常量、函数、过程等,返回指向给定实体地址的指针。而Ptr函数只接受值为整数类型的地址表达式(例子中直接传递了整数A),返回指定地址的指针。在上面的例子中,使用了类型转换,即 A := Integer(P); 语句中,将指针转换为用整数类型表示的地址。