函数的指针

原创
2016/10/22 16:37
阅读数 150

1.C语言中的函数指针

    C语言中的指针可以指向整型、字符型或者结构体类型,同样也可以指向一个函数,这就是函数的指针。函数指针的值等于该函数存放其二进制执行代码的内存区域的首地址:

函数指针的一般声明形式如下:

函数的返回值  (*指针变量名)(函数的参数列表);

例如:

int (*p)(int, int);

该变量声明了一个指针变量p,其指向的内容是一个函数。该函数的返回值是一个整型,其参数也是两个整型变量。声明了一个函数指针后就可以对其进行赋值。函数名的本质是存放函数代码的内存空间的首地址,因此可以将一个函数名赋值给一个指向函数的指针,之后这个函数指针就可以表示这个函数了:

p = f;

表示将f()的存储空间的首地址赋值给函数指针p,p指向f()这个函数。引用指针就相当于调用这个函数:

(*p)(1, 2);
//等价于
f(1, 2);

下面的程序演示了用函数指针实现两个整数的四则运算:

/**
 * common.h  声明全局变量和外部函数的头文件
 */

#include <stdio.h>

//声明四个全局变量
extern int (*p1)(int , int); //引用加法函数
extern int (*p2)(int , int); //引用减法函数
extern int (*p3)(int , int); //引用乘法函数
extern int (*p4)(int , int); //引用除法函数

//四则运算函数声明
int add(int a, int b);  //加法函数
int sub(int a, int b);  //减法函数
int mul(int a, int b);  //乘法函数
int div(int a, int b);  //除法函数
/**
 * lib.c 定义全局变量和四则运算函数
 */

#include "common.h"

//全局变量定义
int (*p1)(int , int) = NULL;
int (*p2)(int , int) = NULL;
int (*p3)(int , int) = NULL;
int (*p4)(int , int) = NULL;

//四则运算函数

//加法函数
int add(int a, int b)
{
  return a + b;
}
//减法函数
int sub(int a, int b)
{
  return a - b;
}
//乘法函数
int mul(int a, int b)
{
  return a * b;
}
//除法函数
int div(int a, int b)
{
  return a / b;
}

在main函数中调用四则运算函数:

#include "common.h"

int main(void)
{
  int a, b, res;

  //使用四个全局变量的函数指针来引用这四个函数
  p1 = add;
  p2 = sub;
  p3 = mul;
  p4 = div;
  a = 2;
  b = 1;
  printf("add : %d\n", (*p1)(a, b));
  printf("sub : %d\n", (*p2)(a, b));
  printf("mul : %d\n", (*p3)(a, b));
  printf("div : %d\n", (*p4)(a, b));
  
  return 0;
}

运行结果:

 

2.回调函数

假设有一个max()函数可以在任意一组对象中找到键码最大的对象,这些对象可能是一些整数,也可能是一些结构体。

为了将max()函数实现的更加通用,可以将其适用于任何对象,因此需要由调用max()函数的调用者自己提供一个比较两个对象的函数作为标准,这两个比较函数就是回调函数。

下面演示max函数的实现:

在main函数中调用max()函数,分别比较寻找一个整型数组中的最大值和一个存储图书信息的结构体数组中图书id最大的图书结构体。

/**
 * common.h  声明全局变量和外部函数的头文件
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**
 * 定义一个自定义类型的函数指针,返回值是整数,两个参数是两个任意类型的指针
 * 该函数的两个参数分别是需要比较的两个对象,在比较时将其转换
 * 如果大于则返回1,等于则返回0,小于则返回-1
 */
typedef int (*cmp)(void *, void *);
typedef struct book* Book;

/**
 * 图书结构:
 *  id:图书的编号
 *  name:图书的名字
 */
struct book{
  int id;
  char name[10];
};

//求最大对象的函数
extern void *max(void *array[], int len, cmp func);
//比较两个整数的函数
extern int cmp_int(void *p, void *q);
//比较两个图书结构的函数
extern int cmp_struct(void *p, void *q);
//插入一个结构
extern int insert_struct(Book *pos, int id, char * name);
//插入一个整数
extern int insert_int(int **pos, int val);
/**
 * max.c  实现max()函数和用作对象比较的回调函数
 */

#include "common.h"

/**
 * 求序列中最大对象的函数,并且返回最大对象的位置
 *   array:存储对象的数组,每个元素是一个指向对象的指针
 *   len:存储对象的数组的元素个数
 *   func:用于比较两个对象的回调函数
 */
void *max(void *array[], int len, cmp func)
{
  int i;
  void *tmp;
  tmp = array[0]; //初始时最大对象是数组的第一个对象
  for(i = 1; i < len; i++){
    //比较两个对象,调用用户提供的比较函数
    //如果当前对象大于之前的对象,则替换掉对打对象
    if((*func)(tmp, array[i]) == -1) {
      tmp = array[i];
    }
  }
  return tmp; //返回最大对象
}
/**
 * cmp.c  定义比较两个对象的回调函数
 */

#include "common.h"

int cmp_int(void *p, void *q)
{
  int *a, *b;
  a = (int *)p;  //将参数中void*类型指针转换为int型的指针
  b = (int *)q;
  if(*a > *b) {  //比较两个值的大小
    return 1;
  } else if(*a < *b){
    return -1;
  } else{
    return 0;
  }
}

int cmp_struct(void *p, void *q)
{
  Book a, b;
  a = (Book)p;  //将参数中void*类型的指针转换为Book类型的指针
  b = (Book)q;
  if(a->id > b->id){
    return 1;
  } else if(a->id < b->id){
    return -1;
  } else{
    return 0;
  }
}
/**
 * obj.c  定义与对象相关的输入函数
 */

#include "common.h"

/**
 * 创建一个图书结构,并将其插入到指定的位置
 *   pos:保存新创建的结构体的数组的指针,注意这是一个指向Book指针类型的指针
 *   id:新结构体的id
 *   name:新结构体的name
 * 如果成功创建一个新结构体并将其设置到指定位置,则返回0,失败返回-1
 */
int insert_struct(Book *pos, int id, char *name)
{
  Book p;
  p = (Book)malloc(sizeof(struct book)); //分配一个空间
  if(p == NULL){
    perror("fail to malloc");
    return -1;
  }
  p->id = id;
  strcpy(p->name, name);  //对结构体变量进行赋值
  *pos = p;  //将结构体变量赋值到数组中
  return 0;
}

//为了统一模式,添加一个插入整型元素的函数,这个函数也可以不要
int insert_int(int **pos, int val)
{
  int *p;
  p = (int *)malloc(sizeof(int)); //分配一个整型数据
  *p = val;
  *pos = p;
  return 0;
}

在main函数中使用:

#include "common.h"

#define MAX 3

int main(void)
{
  Book array1[MAX];  //结构体变量的数组
  int *array[MAX];   //整型变量的数组
  int i, id, val;
  char name[10];
  Book res1;
  int *res2;
  for(i = 0; i < MAX; i++){
    printf("input info of book\n");
    scanf("%d", &id);
    scanf("%s", name);
    if(insert_struct(array1 + i, id, name) == -1){
      exit(1);
    }
    printf("input int\n");
    scanf("%d", &val);
    if(insert_int(array + i, val) == -1){
      exit(1);
    }
  }

  res1 = (Book)max((void **)array1, MAX, cmp_struct);//得到id最大的图书结构
  res2 = (int *)max((void **)array, MAX, cmp_int);//得到最大的整型元素
  printf("the max of books : %d, %s\n", res1->id, res1->name);
  printf("the max of int : %d\n", *res2);
  
  return 0;
}

运行结果为:

回调函数在C语言中的应用是很广泛的,这使得C语言中提供泛型函数成为可能,同事也使得代码的通用性更强,但是同样会使代码的数量变得庞大而且执行效率不那么高。

 

3.函数指针数组

C语言中可以出现函数指针的数组,该数组中的每一个元素是一个函数的指针。一般的定义如下:

函数返回值  (*数组名[元素个数])(参数列表);

例如:

int (*f[10])(int , int);

该定义表示定义了一个数组f,其数组中每个元素是一个指针。该指针是一个指向函数的指针,该函数拥有一个整型返回值,两个整型的参数。这个函数指针数组共有10个元素。

下面的例子定义和使用函数数组的实例:

#include <stdio.h>

//加法函数
int add(int a, int b)
{
  return a + b;
}
//乘法函数
int mul(int a, int b)
{
  return a * b;
}

int main(void)
{
  /**
   * 定义一个函数指针的数组
   * 这个数组名为op,数组共有两个元素,每个元素是一个函数指针
   * 这个函数指针指向一个有一个整型返回值,两个整型参数的函数
   */
  int (*op[2])(int a, int b);
  op[0] = &add;  //第一个指向add()函数
  op[1] = &mul;  //第二个指向mul()函数
  printf("%d %d\n", op[0](1, 2), op[1](1, 2));

  return 0;
}

运行结果:

 

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
2 收藏
0
分享
返回顶部
顶部