level 6
西安恩仪联教育
楼主
本文由西安恩仪联科技有限工作整理和发布,如要引用请注明出处,尊重原版。
目录:
1、什么是函数指针。
2、函数指针使用语法。
3、函数指针工程中使用案例。
一、什么是函数指针
c语言中有一种重要的指针叫函数指针,多数初学者由于工程经验有限对其一知半解,甚至刚毕业的本科生都没有听过此概念,自己曾经在学校学习了一学期的c语言程序设计,却对此概念全然不知。用c开发项目时,不管是底层驱动编程,还是应用层服务器编程或者基于实时系统的嵌入式开发,函数指针都起着非常重要的作用。是一个合格的c开发者必须要掌握的技术点,很多求职者在面试c岗位工程师都会被问到此问题,这就有力证明了它在工程开发中的重要性。
我们大家都知道指针是地址的形象化描述,指针就是地址,仅是另一种说法而已。整形指针就是存放整形数空间的起始地址,字符型指针是存放字符串的内存空间的起始地址,那么函数指针是不是应该理解为函数在内存中的起始地址,函数有地址没有?理解完全正确,函数指针就是函数在内存中的起始地址,函数当然是有地址的,函数中每一句话都是有地址的。通常计算机是将代码读入到内存中后才开始执行的,读入到内存中就必然占用内存空间,内存空间的地址就是每一句话的地址。c中通过找到函数指针才能调用函数,使函数运行。Cpu的工作可以理解为通过指针找内存空间,获取内存空间中的指令(代码),然后运行代码,所以运行代码之前必须要获取代码的地址,才能找到代码,进而才能执行。
所以函数指针就是函数在内存中的起始地址,通常用函数名表示,函数名就代表了函数在内存中的起始地址。下面代码展示:
#include <stdio.h>
int add(int data1,int data2)
{
int res = 0;
res = data1 + data2;
return res;
}
int main()
{
printf("%p\n",add);
printf("%p %p\n",add,&add);
return 0;
}
运行后结果如下:
通过这里例子让大家直观认识函数指针,能够完全看到函数指针。那么研究函数指针的目的是什么,为什么很多学习过c编程的人不知道它的存在,也从来没有用过。因为这个技术点在c中本来就是一个比较高级话题,初学者没有学习过,甚至学习过的人都感觉没有什么用处。我首先给出结论:多数情况下研究函数指针的目的是为了解决函数作为函数的参数这种问题的,因为大家没有设计过或者调用过这种函数,所以就不知道它的存在。随着编程经验的增加这个技术点必然是大家要掌握的。接下来我给出使用它的语法规则和工程案例,帮助各位迅速掌握和理解它。
一、函数指针的语法
使用指针变量的三步骤:定义指针变量、指向一个合法空间、通过指针变量操作该空间中的数据。使用函数指针变量同样的是三个步骤:第一步:定义指针变量;第二步:使指针变量指向一个函数;第三步:注意不是操作数据,使通过指针变量调用函数。
1、如何定义指针变量。
定义函数指针变量的语法在c中是定义所有指针变量语法中最繁杂的语法,函数指针变量的类型是由函数的接口决定的,跟函数的功能没有关系。定义的语法如下:
返回值类型 (*函数指针变量名)(形参类型1,形参类型2,...) = NULL;
例如定义一个指向add函数的指针变量,add函数如下
int add(int data1,int data2) { int res = 0; res = data1 + data2; return res; }
定义函数指针变量pfun:Int (*pfun)(int,int) = NULL;
pfun指向函数add: pfun = add;
2、指向和使用函数指针变量
int (*pfun)(int,int) = NULL; pfun = add;
通过函数指针变量pfun调用add函数的语法:
Int res = 0; res = (*pfun)(12,23)
定义并使用函数指针变量的目的是通过函数指针调用它所指向的函数。
3、给函数指针类型起别名并使用
由于定义函数指针变量的语法过于复杂,c中允许给函数指针类型起别名,用别名定义函数指针变量或者函数指针数组。语法如下:
typedef 返回值类型 (*类型名)(形参类型1,形参类型2,...);
这个语法不用于一般的给类型起别名的语法,大家要注意。
例如:上面定义一个指向add函数的指针变量就可以简写为如下形式:
原定义:
int (*p)(int,int) = NULL; 简化为: typedef int(*PFUN)(int,int);//起别名 PFUN p = NULL;//定义指针变量p
三、函数指针工程中使用案例。
多数初学者学习了函数指针的概念后感觉没有什么作用,这是因为代码量没有到一定的程度或者没有接触过真实的项目开发。开发软件大家必须学习一门课程,叫《高级编程技术》又称为《应用开发编程技术》。其中主要讲解数据存储技术、多任务编程技术、网络编程技术,这些都是一个企业级项目必须掌握的技术。本次从该方向的列举函数指针的作用,如果大家有该方面的知识基础就能够理解我下面列举的三个方面的应用;如果没有学习过,就必须先学习这门课程,才能真正领会函数指针的作用。
案例1:进程编程中有一个进程间通信的方式,叫信号通信。进程收到信号后执行指定的函数,需要给进行安装一个执行的函数。信号安装函数的原型如下:
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
其中使用函数指针,只有先理解函数指针,才能很好理解进程之间通信。
案例2:c语言编写代码时,工程中经常需要使用多线程,就需要创建线程。c中创建线程的函数声明如下:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
大家注意该函数的第三个参数,就是定义一个函数指针变量作为形参。
案例3:用c编写linux驱动程序时,需要用到一个基础的结构体
Struct file_operations,它的成员定义如下:
struct file_operations
{
struct module *owner; // 拥有该结构的模块的指针
loff_t (*llseek)(struct file *, loff_t, int); // 改变文件位置
ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); // 从设备读取数据
ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); // 向设备写入数据
ssize_t (*aio_read)(struct kiocb *, const struct iovec *, unsigned long, loff_t); // 异步读取操作
ssize_t (*aio_write)(struct kiocb *, const struct iovec *, unsigned long, loff_t); // 异步写入操作
int (*readdir)(struct file *, void *, filldir_t); // 读取目录(对于设备文件,此字段为NULL)
unsigned int (*poll)(struct file *, struct poll_table_struct *); // 轮询函数
int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long); // 设备控制操作
long (*unlocked_ioctl)(struct file *, unsigned int, unsigned long); // 解锁的设备控制操作
long (*compat_ioctl)(struct file *, unsigned int, unsigned long); // 兼容设备控制操作
int (*mmap)(struct file *, struct vm_area_struct *); // 内存映射操作
int (*open)(struct inode *, struct file *); // 打开设备操作
int (*flush)(struct file *, fl_owner_t id); // 清空操作
int (*release)(struct inode *, struct file *); // 释放设备操作
};
该结构体中除了第一个成员以外,其它的成员都是函数指针。这个结构体是linux驱动开发中的一个基础的结构体,必须明白函数指针概念才能理解它的作用。再此不在过多的赘述,大家可以查阅相关资料学习如何编写驱动程序。
2025年08月21日 03点08分
1
目录:
1、什么是函数指针。
2、函数指针使用语法。
3、函数指针工程中使用案例。
一、什么是函数指针
c语言中有一种重要的指针叫函数指针,多数初学者由于工程经验有限对其一知半解,甚至刚毕业的本科生都没有听过此概念,自己曾经在学校学习了一学期的c语言程序设计,却对此概念全然不知。用c开发项目时,不管是底层驱动编程,还是应用层服务器编程或者基于实时系统的嵌入式开发,函数指针都起着非常重要的作用。是一个合格的c开发者必须要掌握的技术点,很多求职者在面试c岗位工程师都会被问到此问题,这就有力证明了它在工程开发中的重要性。
我们大家都知道指针是地址的形象化描述,指针就是地址,仅是另一种说法而已。整形指针就是存放整形数空间的起始地址,字符型指针是存放字符串的内存空间的起始地址,那么函数指针是不是应该理解为函数在内存中的起始地址,函数有地址没有?理解完全正确,函数指针就是函数在内存中的起始地址,函数当然是有地址的,函数中每一句话都是有地址的。通常计算机是将代码读入到内存中后才开始执行的,读入到内存中就必然占用内存空间,内存空间的地址就是每一句话的地址。c中通过找到函数指针才能调用函数,使函数运行。Cpu的工作可以理解为通过指针找内存空间,获取内存空间中的指令(代码),然后运行代码,所以运行代码之前必须要获取代码的地址,才能找到代码,进而才能执行。
所以函数指针就是函数在内存中的起始地址,通常用函数名表示,函数名就代表了函数在内存中的起始地址。下面代码展示:
#include <stdio.h>
int add(int data1,int data2)
{
int res = 0;
res = data1 + data2;
return res;
}
int main()
{
printf("%p\n",add);
printf("%p %p\n",add,&add);
return 0;
}
运行后结果如下:
通过这里例子让大家直观认识函数指针,能够完全看到函数指针。那么研究函数指针的目的是什么,为什么很多学习过c编程的人不知道它的存在,也从来没有用过。因为这个技术点在c中本来就是一个比较高级话题,初学者没有学习过,甚至学习过的人都感觉没有什么用处。我首先给出结论:多数情况下研究函数指针的目的是为了解决函数作为函数的参数这种问题的,因为大家没有设计过或者调用过这种函数,所以就不知道它的存在。随着编程经验的增加这个技术点必然是大家要掌握的。接下来我给出使用它的语法规则和工程案例,帮助各位迅速掌握和理解它。
一、函数指针的语法
使用指针变量的三步骤:定义指针变量、指向一个合法空间、通过指针变量操作该空间中的数据。使用函数指针变量同样的是三个步骤:第一步:定义指针变量;第二步:使指针变量指向一个函数;第三步:注意不是操作数据,使通过指针变量调用函数。
1、如何定义指针变量。
定义函数指针变量的语法在c中是定义所有指针变量语法中最繁杂的语法,函数指针变量的类型是由函数的接口决定的,跟函数的功能没有关系。定义的语法如下:
返回值类型 (*函数指针变量名)(形参类型1,形参类型2,...) = NULL;
例如定义一个指向add函数的指针变量,add函数如下
int add(int data1,int data2) { int res = 0; res = data1 + data2; return res; }
定义函数指针变量pfun:Int (*pfun)(int,int) = NULL;
pfun指向函数add: pfun = add;
2、指向和使用函数指针变量
int (*pfun)(int,int) = NULL; pfun = add;
通过函数指针变量pfun调用add函数的语法:
Int res = 0; res = (*pfun)(12,23)
定义并使用函数指针变量的目的是通过函数指针调用它所指向的函数。
3、给函数指针类型起别名并使用
由于定义函数指针变量的语法过于复杂,c中允许给函数指针类型起别名,用别名定义函数指针变量或者函数指针数组。语法如下:
typedef 返回值类型 (*类型名)(形参类型1,形参类型2,...);
这个语法不用于一般的给类型起别名的语法,大家要注意。
例如:上面定义一个指向add函数的指针变量就可以简写为如下形式:
原定义:
int (*p)(int,int) = NULL; 简化为: typedef int(*PFUN)(int,int);//起别名 PFUN p = NULL;//定义指针变量p
三、函数指针工程中使用案例。
多数初学者学习了函数指针的概念后感觉没有什么作用,这是因为代码量没有到一定的程度或者没有接触过真实的项目开发。开发软件大家必须学习一门课程,叫《高级编程技术》又称为《应用开发编程技术》。其中主要讲解数据存储技术、多任务编程技术、网络编程技术,这些都是一个企业级项目必须掌握的技术。本次从该方向的列举函数指针的作用,如果大家有该方面的知识基础就能够理解我下面列举的三个方面的应用;如果没有学习过,就必须先学习这门课程,才能真正领会函数指针的作用。
案例1:进程编程中有一个进程间通信的方式,叫信号通信。进程收到信号后执行指定的函数,需要给进行安装一个执行的函数。信号安装函数的原型如下:
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
其中使用函数指针,只有先理解函数指针,才能很好理解进程之间通信。
案例2:c语言编写代码时,工程中经常需要使用多线程,就需要创建线程。c中创建线程的函数声明如下:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
大家注意该函数的第三个参数,就是定义一个函数指针变量作为形参。
案例3:用c编写linux驱动程序时,需要用到一个基础的结构体
Struct file_operations,它的成员定义如下:
struct file_operations
{
struct module *owner; // 拥有该结构的模块的指针
loff_t (*llseek)(struct file *, loff_t, int); // 改变文件位置
ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); // 从设备读取数据
ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); // 向设备写入数据
ssize_t (*aio_read)(struct kiocb *, const struct iovec *, unsigned long, loff_t); // 异步读取操作
ssize_t (*aio_write)(struct kiocb *, const struct iovec *, unsigned long, loff_t); // 异步写入操作
int (*readdir)(struct file *, void *, filldir_t); // 读取目录(对于设备文件,此字段为NULL)
unsigned int (*poll)(struct file *, struct poll_table_struct *); // 轮询函数
int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long); // 设备控制操作
long (*unlocked_ioctl)(struct file *, unsigned int, unsigned long); // 解锁的设备控制操作
long (*compat_ioctl)(struct file *, unsigned int, unsigned long); // 兼容设备控制操作
int (*mmap)(struct file *, struct vm_area_struct *); // 内存映射操作
int (*open)(struct inode *, struct file *); // 打开设备操作
int (*flush)(struct file *, fl_owner_t id); // 清空操作
int (*release)(struct inode *, struct file *); // 释放设备操作
};
该结构体中除了第一个成员以外,其它的成员都是函数指针。这个结构体是linux驱动开发中的一个基础的结构体,必须明白函数指针概念才能理解它的作用。再此不在过多的赘述,大家可以查阅相关资料学习如何编写驱动程序。