C函数指针

来源:互联网 发布:数据漫游是什么意思 编辑:程序博客网 时间:2024/06/17 10:37

内存可以视为一个线性数组。如果一个变量保存的值是内存数组的索引(值),这样的变量称为指针。【许多C语言的书中,似乎说指针是特殊类型的通称,即指针类型,如同数组是int[]、char[]等等的通称;谭C的指针是指指针变量的值即一个内存数组的索引、一个地址。K&R指指针变量。】

函数指针(Function Pointers),也是一个指针变量,保存一个函数在内存中的入口地址。

1.函数名与函数签名

C语言中,函数名是编译后的代码在内存中的起始地址;类比,数组名是一个数组在内存中的起始地址。C语言的内存模型中的四个存储区,函数名位于代码区的二进制的机器代码(.text)部分。

函数签名,指一个函数的返回值类型、函数名和形参列表。【许多Java语言的书中,方法签名的界定并不一致。大多数情况下,指函数名和形参列表,参见《编程导论(Java)》p59】
函数指针,总是指向特定签名的函数。可以将各种函数名赋值给一个函数指针,但是这些函数除函数名外,必须具有相同的返回值类型和形参列表——这些也即函数指针的类型。

2.函数指针的用途

  • 实现回调(callback)
  • 替代分支结构

3.替代分支结构

现有int的四则运算函数4枚,主函数希望按照某个参数(例如char op)决定调用某个函数。
#include <stdio.h> int Plus    (int a, int b) { return a+b; }int Minus   (int a, int b) { return a-b; }int Multiply(int a, int b) { return a*b; }int Divide  (int a, int b) { return a/b; }/**switch-statement:op决定执行哪一种操作*/void Switch(int a, int b, char op){   int result=0;   switch(op){      case '+' : result = Plus     (a, b); break;      case '-' : result = Minus    (a, b); break;      case '*' : result = Multiply (a, b); break;      case '/' : result = Divide   (a, b); break;   }   printf("Switch: %d %c %d = %d\n",a,op,b,result);}int main(void){   Switch(2,3,'+');   return 0;}
我们编写Switch函数的替代品:以函数指针pt2Func为参数
void Switch_With_Function_Pointer(int a, int b, int (*pt2Func)(int, int)){int result = pt2Func(a, b);    // call using function pointerprintf("Switch_With_Function_Pointer: %p (%d ,%d) = %d\n",pt2Func,a,b,result);}int main(void){Switch(2,3,'+');Switch_With_Function_Pointer(2, 5,  &Minus);// Pass a Function Pointer as an Argument return 0;}
输出:
Switch: 2 + 3 = 5
Switch_With_Function_Pointer: 004010e0 (2 ,5) = -3
注: Pelles c没有execinfo.h ,不方便根据函数指针输出函数名,

4.函数指针的相关语法

定义函数指针pt2Func:
int (*pt2Func)(int, int) = NULL;   //Define a Function Pointer
void Switch_With_Function_Pointer(int a, int b, int (*pt2Func)(int, int)){ //as a param
函数指针pt2Func的类型:int (*)(int, int)

赋值(实参):
pt2Func = &Minus;  //标准
pt2Func = Minus;  //简写

调用:
int result1 = (*pt2Func) (2,3);   //标准
int result2 = pt2Func (2,3);   //简写,容易使人误解pt2Func是一个函数。
int result3 = Plus(2,3);   // 比较
int result4 = (***Plus) (2,3);   //如果你稀罕

5.回调

回调的原始含义:
回调通常指可以被作为参数传递给其他代码的可执行代码块,或者一个可执行代码的引用
参考 《编程导论(Java)·9.3.1Java回调-2》
在设计一个基础库函数时——假设void Switch_With_Function_Pointer(int a, int b, int (*pt2Func)(int, int))是某个标准库函数,设计者不知道使用者需要何种操作代码——Plus还是Minus等等,于是以函数指针pt2Func为占位符,而Plus或Minus作为实参传递给 Switch_With_Function_Pointer。
因此,在Java中,基础库如IClient定义的抽象方法callback(int) 被称为回调接口,IClient的子类型如Client给出的callback实现被称为回调(函数)。C语言中——没有多态,作为实参传递的int (*)(int, int)函数如Plus还是Minus,也即回调(函数)。
其实质,用户为基础库函数提供自己的代码。
如果Switch_With_Function_Pointer让你觉得不像基础库函数,你可以使用stdlib.h中声明的,常用的qsort函数。
extern void __cdecl qsort(void *, size_t, size_t, __cmpfunc *);
#include <stdlib.h>        //          qsort#include <time.h>          //          randomize#include <stdio.h>         //          printf#define ARRAY_SIZE 10int CmpFunc(const void* _a, const void* _b){const float* a = (const float*) _a;const float* b = (const float*) _b;return (*a > *b)? 1: (*a == *b)? 0:-1;}void QSortDemo(void){float field[ARRAY_SIZE];time_t t;srand((unsigned) time(&t));for(int c=0;c<ARRAY_SIZE;c++)             // randomize all elements of the fieldfield[c]=rand();qsort((void*) field, /*number of items*/ ARRAY_SIZE, /*size of an item*/ sizeof(field[0]),            /*comparison-function*/ CmpFunc);printf("the sorted field are ...\n");for(int c=0;c<ARRAY_SIZE;c++)printf("element #%d contains %.0f\n", c, field[c]);printf("\n");}

6.返回一个函数指针

//Return a Function Pointer int (*GetPtr(const char op))(int, int){return '+'==op ? &Plus : &Minus;}void QSortDemo(void);int main(void){int (*pt2Func)(int, int) = NULL;pt2Func = GetPtr('+');int result2 = (*pt2Func) (2,3);  printf("result2 = %d\n",result2);QSortDemo();return 0;}





0 0
原创粉丝点击