Chapter 5

来源:互联网 发布:家庭网络布线用光纤 编辑:程序博客网 时间:2024/05/18 06:03

5.11 Pointers to Functions

In C, a function itself is not a variable, but it is possible to define pointers to functions, which can be assigned, placed in arrays, passed to functions, returned by functions, and so on. We will illustrate this by modifying the sorting procedure written earlier in this chapter so that if the optional argument -n is given, it will sort the input lines numerically instead of lexicographically.

 C 语言中,函数本身不是变量,但可以定义指向函数的指针。这种类型的指针可以被赋值、存放在数组中、传递给函数以及作为函数的返回值等等。为了说明指向函数的指针的用法,我们接下来将修改本章前面的排序函数,在给定可选参数-n 的情况下,该函数将按数值大小而非字典顺序对输入行进行排序。

A sort often consists of three parts - a comparison that determines the ordering of any pair of objects, an exchange that reverses their order, and a sorting algorithm that makes comparisons and exchanges until the objects are in order. The sorting algorithm is independent of the comparison and exchange operations, so by passing different comparison and exchange functions to it, we can arrange to sort by different criteria. This is the approach taken in our new sort.

排序程序通常包括3 部分:判断任何两个对象之间次序的比较操作、颠倒对象次序的交换操作、一个用于比较和交换对象直到所有对象都按正确次序排列的排序算法。由于排序算法与比较、交换操作无关,因此,通过在排序算法中调用不同的比较和交换函数,便可以实现按照不同的标准排序。这就是我们的新版本排序函数所采用的方法。

Lexicographic comparison of two lines is done by strcmp, as before; we will also need a routine numcmp that compares two lines on the basis of numeric value and returns the same kind of condition indication as strcmp does. These functions are declared ahead of main and a pointer to the appropriate one is passed to qsort. We have skimped on error processing for arguments, so as to concentrate on the main issues.

我们在前面讲过,函数strcmp 按字典顺序比较两个输入行。在这里,我们还需要一个以数值为基础来比较两个输入行,并返回与strcmp同样的比较结果的函数numcmp。这些函数在main 之前声明,并且,指向恰当函数的指针将被传递给qsort 函数。在这里,参数的出错处理并不是问题的重点,我们将主要考虑指向函数的指针问题。

#include <stdio.h>

#include <string.h>

#define MAXLINES 5000 /* max #lines to be sorted */

char *lineptr[MAXLINES]; /* pointers to text lines */

int readlines(char *lineptr[], int nlines);

void writelines(char *lineptr[], int nlines);

void qsort(void *lineptr[], int left, int right,

int (*comp)(void *, void *));

int numcmp(char *, char *);

/* sort input lines */

main(int argc, char *argv[])

{

int nlines; /* number of input lines read */

int numeric = 0; /* 1 if numeric sort */

if (argc > 1 && strcmp(argv[1], "-n") == 0)

numeric = 1;

if ((nlines = readlines(lineptr, MAXLINES)) >= 0) {

qsort((void**) lineptr, 0, nlines-1,

(int (*)(void*,void*))(numeric ? numcmp : strcmp));

writelines(lineptr, nlines);

return 0;

} else {

printf("input too big to sort\n");

return 1;

}

}

In the call to qsort, strcmp and numcmp are addresses of functions. Since they are known to be functions, the & is not necessary, in the same way that it is not needed before an array name.

在调用函数qsort的语句中,strcmpnumcmp 是函数的地址。因为它们是函数,所以前面不需要加上取地址运算符&,同样的原因,数组名前面也不需要&运算符。

We have written qsort so it can process any data type, not just character strings. As indicated by the function prototype, qsort expects an array of pointers, two integers, and a function with two pointer arguments. The generic pointer type void * is used for the pointer arguments. Any pointer can be cast to void * and back again without loss of information, so we can call qsort by casting arguments to void *. The elaborate cast of the function argument casts the arguments of the comparison function. These will generally have no effect on actual representation, but assure the compiler that all is well.

改写后的qsort 函数能够处理任何数据类型,而不仅仅限于字符串。从函数qsort 原型可以看出,它的参数表包括一个指针数组、两个整数和一个有两个指针参数的函数。其中,指针数组参数的类型为通用指针类型void *。由于任何类型的指针都可以转换为void*类型,并且在将它转换回原来的类型时不会丢失信息,所以,调用qsort 函数时可以将参数强制转换为void *类型。比较函数的参数也要执行这种类型的转换。这种转换通常不会影响到数据的实际表示,但要确保编译器不会报错。

/* qsort: sort v[left]...v[right] into increasing order */

void qsort(void *v[], int left, int right,int (*comp)(void *, void *))

{

int i, last;

void swap(void *v[], int, int);

if (left >= right) /* do nothing if array contains */

return; /* fewer than two elements */

swap(v, left, (left + right)/2);

last = left;

for (i = left+1; i <= right; i++)

if ((*comp)(v[i], v[left]) < 0)

swap(v, ++last, i);

swap(v, left, last);

qsort(v, left, last-1, comp);

qsort(v, last+1, right, comp);

}

The declarations should be studied with some care. The fourth parameter of qsort is

int (*comp)(void *, void *)

which says that comp is a pointer to a function that has two void * arguments and returns an int.

The use of comp in the line

if ((*comp)(v[i], v[left]) < 0)

is consistent with the declaration: comp is a pointer to a function, *comp is the function, and

(*comp)(v[i], v[left])

is the call to it. The parentheses are needed so the components are correctly associated; without them,

int *comp(void *, void *) /* WRONG */

says that comp is a function returning a pointer to an int, which is very different.

We have already shown strcmp, which compares two strings. Here is numcmp, which compares two strings on a leading numeric value, computed by calling atof:

#include <stdlib.h>

/* numcmp: compare s1 and s2 numerically */

int numcmp(char *s1, char *s2)

{

double v1, v2;

v1 = atof(s1);

v2 = atof(s2);

if (v1 < v2)

return -1;

else if (v1 > v2)

return 1;

else

return 0;

}

The swap function, which exchanges two pointers, is identical to what we presented earlier in the chapter, except that the declarations are changed to void *.

void swap(void *v[], int i, int j;)

{

void *temp;

temp = v[i];

v[i] = v[j];

v[j] = temp;

}

A variety of other options can be added to the sorting program; some make challenging exercises.


原创粉丝点击