The C Programming Language(第 2 版) 笔记 / 5 指针与数组 / 5.11 指向函数的指针

目录、参考文献


5.11 指向函数的指针

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

排序程序通常包括 3 部分:

  1. 判断任何两个对象之间次序的比较操作
  2. 颠倒对象次序的交换操作
  3. 一个用于比较和交换对象直到所有对象都按正确次序排列的排序算法

由于排序算法与比较、交换操作无关
因此,通过在排序算法中调用不同的比较和交换函数,便可以实现按照不同的标准排序
这就是我们的新版本排序函数所采用的方法

对比 Java 中的 Comparator 接口
可以看出,Java 多态的本质就是用接口或父类作为函数指针来编程
通过运行时动态传入的具体的指针来动态切换指向的函数实现

我们在前面讲过,函数 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; 
    } 
}

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

改写后的 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); 
}

qsort 函数的第四个参数声明为 int (*comp)(void *, void *)
它表明 comp 是一个指向函数的指针,该函数具有两个 void * 类型的参数
其返回值类型为 int

语句 if ((*comp)(v[i], v[left]) < 0) 中的 comp 的使用和其声明是一致的
comp 是一个指向函数的指针,*comp 代表一个函数
语句 (*comp)(v[i], v[left]) 对该函数进行调用

其中的圆括号是必须的,这样才能够保证其中的各个部分正确结合
如果没有括号,例如写成 int *comp(void *, void *) /* WRONG */
则表明 comp 是一个函数,该函数返回一个指向 int 类型的指针

我们在前面讲过函数 strcmp,用于比较两个字符串
这里介绍的函数 numcmp 也是比较两个字符串
但它通过调用 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; 
}

交换两个指针的 swap 函数和本章前面所述的 swap 函数相同
但它的参数声明为 void * 类型

void swap(void *v[], int i, int j;) 
{ 
    void *temp; 
    temp = v[i]; 
    v[i] = v[j]; 
    v[j] = temp; 
}

目录、参考文献

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值