《C和C++代码精粹》——2.12 指向函数的指针

简介:

本节书摘来自异步社区出版社《C和C++代码精粹》一书中的第2章,第2.12节,作者: 【美】Chuck Allison,更多章节内容可以访问云栖社区“异步社区”公众号查看。

2.12 指向函数的指针

C和C++代码精粹
一个指针可以指向函数也可以指向存储的对象。下面的语句声明fp是一个指向返回值为整型(int)的函数的指针:

int(*fp)( );

*ftp的圆括号是必需的,没有它的语句

int *fp( );

将fp声明为一个返回指向整型(int)指针的函数。这就是将星号与类型声明紧密相连的方式成为逐渐受人们欢迎的方式的原因之一。

int* fp();    //方式说明fp()返回一个指向整型的指针(int * )

当然,这种方式建议你通常应该每条语句只声明一个实体,否则,以下的语句将会使人感到迷惑:

int *ip, jp;  //jp不是一个指针!

如果想具体说明fp指向的函数就必须带有一定的参数,如果是一个浮点型(float)和一个字符串型,那么可以这样写:

int  (*fp) (float, char * );

然后可以在fp中存储这样一个函数的地址:

extern int g(float,char*);
fp=g;

表达式中函数的名字解析地址可以认为是指向那个函数代码区的开始的地址。下面的“hello,world”程序说明如何通过指针来执行一个函数。

/*hello.c: 通过函数的指针来说hello */
#include <stdio.h>
main()
{
   void ( * fp )( )=printf;
   fp("hello, world\n");
}

要通过指针来执行一个函数,你可能认为得这样写:

(*fp)("hello world\n");

来复引用指针。事实上,在ANSI C出现以前必须这样做,但是ANSI C 委员会决定容许像我在hello.c中那样使用的普通函数调用句法。由于编译器知道它是一个指向函数的指针,并且它还知道在该环境下所能做的惟一的一件事就是调用函数,因此这里没有任何模糊不清的表达。

当把函数名作为一个参数传递给另一个函数时,编译器实际上给这个函数传递了一个指针(与数组名类似)。但是你为什么曾经想过给另一个函数传递函数指针呢?C标准库中的排序函数qsort 的使用就是一个例子,采用简单和复合的排序关键字,它可以对由任何类型的元素所组成的数组排序。程序清单2.17中的程序说明怎样排序命令行参数字符串,在这种情况下所需要做的全部事情就是传递给qsort一个知道如何比较字符串的函数。一个函数(像qsort)通过由运行时决定的指针来调用另一个函数(像 comp)的行为叫做返调(callback)。

函数指针的数组在菜单驱动应用程序中很容易见到,假设想将以下的目录展现给用户:

1.返回

2.插入

3.更新

4.退出

程序清单2.18的程序直接把键盘输入作为索引放到指向处理每一个菜单选择函数的指针的数组中。

程序清单2.17 用qsort函数将命令行参数排序

// sortargs.cpp:  排序命令行参数  
#include <iostream>  
#include <cstring>  
#include <cstdlib>  
using namespace std;  

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

main(int argc, char *argv[])  
{  
    qsort(argv+1, argc-1, sizeof argv[0], comp);  
    while (--argc)  
        cout << *++argv << endl;  
}  

int comp(const void* p1, const void* p2)  
{  
    const char *ps1 = * (const char**) p1;  
    const char *ps2 = * (char**) p2;  
    return strcmp(ps1,ps2);  
}  

//从"sortargs *.cpp"命令输出:  
address.cpp  
arith.cpp  
array1.cpp  
array2.cpp  
array3.cpp  
array4.cpp  
array5.cpp  
array6.cpp  
array7.cpp  
array8.cpp  
array9.cpp  
bit1.cpp  
bit2.cpp  
convert.cpp  
inspect.cpp  
pointer.cpp  
ptr2ptr.cpp  
sortargs.cpp  
swap1.cpp  
swap2.cpp

程序清单2.18 用函数指针数组来处理菜单选择

/* menu.c:  举例说明函数数组*/  
#include <stdio.h>  

/*你一定要给这些提供定义*/  
extern void retrieve(void);  
extern void insert(void);  
extern void update(void);  
extern int show_menu(void);        /*返回keypress */  

main()
{  
  int choice;  
  void (*farray[])(void) = {retrieve,insert,update};  

  for (;;)  
    {  
        choice = show_menu();  
        if (choice >= 1 && choice <= 3)  
            farray[choice-1]();         /* 进程的需要 */  
        else if (choice == 4)  
            break;  
    }  
    return 0;  
}

本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

相关文章
|
5天前
|
C语言 C++ 开发者
深入探索C++:特性、代码实践及流程图解析
深入探索C++:特性、代码实践及流程图解析
|
1天前
|
编译器 C语言 C++
【C++入门学习指南】:函数重载提升代码清晰度与灵活性
【C++入门学习指南】:函数重载提升代码清晰度与灵活性
9 0
|
2天前
|
编译器 C++
【C++进阶】引用 & 函数提高
【C++进阶】引用 & 函数提高
|
5天前
|
设计模式 编译器 数据安全/隐私保护
C++ 多级继承与多重继承:代码组织与灵活性的平衡
C++的多级和多重继承允许类从多个基类继承,促进代码重用和组织。优点包括代码效率和灵活性,但复杂性、菱形继承问题(导致命名冲突和歧义)以及对基类修改的脆弱性是潜在缺点。建议使用接口继承或组合来避免菱形继承。访问控制规则遵循公有、私有和受保护继承的原则。在使用这些继承形式时,需谨慎权衡优缺点。
17 1
|
7天前
|
设计模式 存储 Java
C++从入门到精通:3.5设计模式——提升代码可维护性与可扩展性的关键
C++从入门到精通:3.5设计模式——提升代码可维护性与可扩展性的关键
|
7天前
|
编译器 程序员 C++
C++从入门到精通:3.1模板编程——提高代码的复用性和灵活性
C++从入门到精通:3.1模板编程——提高代码的复用性和灵活性
|
7天前
|
C++
C++从入门到精通:2.1.2函数和类——深入学习面向对象的编程基础
C++从入门到精通:2.1.2函数和类——深入学习面向对象的编程基础
|
7天前
|
存储 C++
C++从入门到精通:2.1.1函数和类
C++从入门到精通:2.1.1函数和类
|
7天前
|
C++
【C++11(三)】智能指针详解--RAII思想&循环引用问题
【C++11(三)】智能指针详解--RAII思想&循环引用问题
|
7天前
|
人工智能 C++
【重学C++】【指针】轻松理解常量指针和指针常量
【重学C++】【指针】轻松理解常量指针和指针常量
9 0