Introduction to Pointers
 
Written by rdc

什么是指针?

指针是一个4字节的数据类型,将地址保存到存储器位置。指针不包含数据,一旦它被初始化,它就指向数据。未初始化的指针指向什么也不定义。

要了解指针,想想一个打印在每个“洞”底部(你放置鸡蛋)的数字1到12的蛋纸箱。这些孔像计算机中的记忆位置一样;每个孔或存储器位置都有一个地址,在本例中为1到12。如果一个蛋代表一个数据项,则孔1中的一个地址为1。

通常,您将通过使用变量直接访问数据。当DIM DIM是特定类型的变量时,您将为数据预留存储空间。您不需要知道或关心数据所在的位置,因为您可以通过变量直接访问数据。这就像在孔1(读数据)中拿出蛋,拿一个鸡蛋放入孔1(设置数据),而不必查看写在孔底部的数字。

使用指针有点不一样。想象一下,你有一点点的纸会代表我们的指针。现在是空白的,不指向任何东西。这个未定义的指针在初始化之前不能使用。要初始化指针,请在其上写入1。现在我们的指针是“指向”我们蛋盒中的孔1。将数据(鸡蛋)放入孔1中,我们看看我们的废纸,将其与孔1匹配,并将鸡蛋放在孔中。要检索蛋,我们做的恰恰相反。我们将我们的纸张与孔1匹配,然后抓住鸡蛋。鸡蛋的所有放置和获取必须通过纸张的纸张完成,并称为取消引用指针。也就是说,我们通过指针中包含的参考数字获得数据,数字1。指针不包含数据;它包含对数据的引用。

在FreeBasic中,我们使用暗淡PTR语句定义了一个指针:

Dim aptr As Integer Ptr



这个声明对应于上述例子中的空白纸。指针不指向任何东西,未定义。如果我们现在试图使用指针,程序就可能会崩溃。

为了使指针变得有用,它必须被初始化:

Dim aptr As Integer Ptr

aptr = Allocate(SizeOf(Integer))



这里我们使用赋值整数的内存中留出足够的空间,并将该空间的地址加载到aptr中。SizeOf宏返回传递数据类型的大小(以字节为单位)。如果你愿意,你可以使用len而不是SizeOf(自.13b)。

一旦我们初始化了指针,我们现在可以使用它:

*aptr = 5
Print "aptr: "; *aptr



注意aptr上的*前缀。*是参考运算符。这就像将纸张上的数字与蛋盒上的孔数相匹配。通过使用*运算符,我们可以得到aptr指向的孔中包含的数据(egg)。

这是一个完整的示例程序:

Option Explicit

Dim aptr As Integer Ptr

aptr = Allocate(SizeOf(Integer))
*aptr = 5
Print "aptr: "; *aptr
Deallocate aptr
Sleep



取消赋值函数释放aptr指向的内存,并再次使aptr未定义。这就像删除我们的纸上的数字。如果我们在取消赋值后使用aptr,程序会崩溃。

指针有什么好处?

添加指向FreeBasic的主要原因是许多外部库需要指向键入结构和指向字符串的指针。例如,Win32 API有许多结构必须填写,然后通过指针传递给一个函数。

指针的另一个用法在于类型定义。类型在FreeBasic中的defs只能包含固定长度的字符串,但是如果在程序运行之前不知道字符串的长度怎么办?指针可以用于此目的。

(应该说,类型定义现在可以支持可变长度的字符串。)

Option Explicit

Type mytptr
    sptr As ZString Ptr
End Type
'This function will allocate space for the passed string
'and load it into a memory location, returning the
'pointer to the string.
Declare Function pSetString(ByVal s As String) As ZString Ptr

'type var
Dim mytype As mytptr

'Set a variable string into the type def
mytype.sptr = pSetString("Hello World From FreeBasic!")
Print "aptr: "; *mytype.sptr
Deallocate(mytype.sptr)
Sleep
End

Function pSetString(ByVal s As String) As ZString Ptr
    Dim sz As ZString Ptr
   
    'allocate some space + 1 for the chr(0)
    sz = Allocate(Len(s) + 1)
    'load the string into the memory location
    *sz = s
    'return the pointer
    Return sz
End Function



这里我们用字段sptr定义我们的类型为ZStringPTR.Zstrings是空终止的字符串,被许多外部库使用,被设计用于动态赋值。一旦我们定义了我们的类型,我们使用暗淡语句创建一个实例:

Dim mytype As mytptr



然后我们调用我们的函数pSetString来获取我们在类型def中所需的可变长度字符串的地址。

mytype.sptr = pSetString("Hello World From FreeBasic!")



记住sptr被定义为一个指针,而不是一个字符串变量,所以pSetString返回一个指针(内存地址)到字符串而不是字符串本身。换句话说,如果字符串在#1中,pSetString返回1。

函数pSetString使用临时ZStringsz,到赋值传递的字符串参数的空间。因为ZString是一个空值终止的字符串,我们必须在赋值函数中为空终止符的长度添加1。

'allocate some space + 1 for the chr(0)
sz = Allocate(Len(s) + 1)



一旦我们为字符串赋值空间,我们使用引用运算符*将数据加载到内存位置。

'load the string into the memory location
*sz = s



然后我们返回一个指针(字符串的地址)回到我们的类型,它保存在mytype.sptr中。

'return the pointer
Return sz



我们现在可以使用引用运算符来引用我们类型中的字符串。

Print "aptr: "; *mytype.sptr



指针可能会让未知的人感到困惑,但是如果记住指针不包含数据,那么它们不需要,它只是指向一些数据。指针是一个内存地址,您可以通过引用运算符*操作该数据。它和一个正常的变量真的没有什么不同。