13.4.4 指针运算

在本章学过,可以给指针加减整型数值。此外,可以比较两个指针来查看它们是否相等或者检测一个指针是大于还是小于另一个指针。指针所允许的其他唯一操作就是相同类型的两个指针的减法。在Objective-C语言中,两指针相减的结果是它们之间所包含的元素个数。这样,如果a是指向任意类型的元素数组,而b指向同一数组中索引值更大的其他元素,那么表达式b-a代表的就是这两个指针之间的元素个数。比如,如果p指向数组x中的某个元素,那么语句


n=p-x;


赋给变量n(假设为整型变量)的是数组x中p指向元素的索引数。所以,如果通过以下语句将p设置为指向x中的第100个元素:


p=&x[99];


那么经过前面的减法运算,n的值应该为99。

函数指针

函数指针的概念有些高级,但出于完整性的考虑,我们在这里介绍它。处理函数指针时,Objective-C编译器不但需要知道指向函数的指针变量,而且要知道函数返回值的类型和参数的数目及类型。要声明变量fnPtr为“指向返回int并且不带参数的函数的指针”,可以编写下面的声明来实现:


int(*fnPtr)(void);


fnPtr两侧的括号是必需的,否则,Objective-C编译器就会认为,在上述语句中,名为fnPtr的函数声明返回一个int指针(因为函数调用运算符()比指针间接寻址运算符的优先级高)。

要使函数指针指向特定函数,可以简单地将函数的名称赋给该指针。因此,如果lookup是返回int并且不带参数的函数,则语句


fnPtr=lookup;


将指向lookup函数的指针存入函数指针变量fnPtr。编写一个函数名称,并且不带随后的一对括号,类似于编写没有下标的数组名称那样。Objective-C编译器将自动产生指向特定函数的指针。允许在函数名称之前添加&标志,但这不是必需的。

如果之前在程序中没有定义函数lookup,则必须在实现前面的赋值运算之前声明该函数。如下语句


int lookup(void);


在将函数指针赋给变量fnPtr之前是必需的。

通过对指针变量应用函数调用运算符,同时在括号内列出该函数的所有参数,可以间接引用指针变量引用的函数。比如


entry=fnPtr();


调用fnPtr所指向的函数,并将返回值存储在变量entry中。

函数指针的一个常见应用是将其作为参数传递给其他函数。Standard Library在函数qsort中用到此应用,该函数实现数组元素的快速排序。它将一个函数指针作为一个参数,只要qsort需要比较待排序的数组中两个元素时,它就会调用这个函数。使用这种方式,qsort可以用来对任何类型的数组进行排序,因为数组中任意两个元素的比较是由用户提供的函数实现的,而不是函数qsort本身。

在Foundation框架中,一些方法使用函数指针作为参数。比如,方法sortUsingFunction:context:定义在类NSMutableArray中,并且无论何时待排序的数组中两个元素需要比较时,就调用指定的函数。

函数指针的另一个常见应用是建立分派表。不能将函数本身保存在数组元素中。然而,可以在数组中存储函数指针。这样,就可以创建包含要调用的函数指针的表。比如,可能创建一个表,用于处理用户输入的不同命令。该表中每项都可以包含命令名称和指向处理这项特定命令要调用的函数的指针。现在,只要用户输入一条命令,就可以查询该表中的命令,并调用相应的函数去处理它。