最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
c语言函数指针是什么意思
时间:2026-09-09 19:43:49 编辑:袖梨 来源:一聚教程网
在前端开发内容学习中,c语言函数指针是什么意思?声明、调用和常见用法详解是常见主题。很多人在阅读时会遇到概念分散、步骤不清和注意点难以归纳的问题。本文按照基础概念、操作流程和关键细节,对相关内容进行整理。

c语言函数指针看起来难,核心其实是用一个指针保存函数入口地址。只要弄清声明格式、赋值方式和调用规则,再结合回调与函数指针数组的场景去练习,理解和使用都会顺畅很多。
函数指针到底是什么
函数指针本质上是一个变量,但它保存的不是普通数据地址,而是某个函数的入口地址。只要函数签名一致,这个指针就可以指向对应函数,并在需要时完成调用。
学习函数指针时最容易混淆的地方,不是概念本身,而是声明语法。因为返回值类型、参数列表和指针符号要同时出现,所以看起来比普通指针更绕。
- 可以把函数指针理解成给函数起一个可传递、可替换的引用名。
- 它常用于回调、策略切换、菜单分发、排序比较函数等场景。
- 判断是不是函数指针,重点看变量名是否被括号和星号一起包住。
易混语法对照
很多人不是不懂函数指针的作用,而是会把几种相似写法看成同一种东西。解决这个问题的关键,是先找到变量名f,再判断它先和谁结合。
如果没有括号,f会先和后面的参数列表结合,表示它是一个函数;如果写成(*f),就强制f先和星号结合,表示它是一个指针,再继续看这个指针指向什么类型的函数。
三种常见写法对照
语法区别示例
int f(int); /* 普通函数:f是函数,接收int,返回int */ int *f(int); /* 返回指针的函数:f是函数,接收int,返回int* */ int (*f)(int); /* 函数指针:f是指针,指向接收int、返回int的函数 */- 先找变量名f,再判断f是函数还是指针。
- 看到(*f)时,括号改变了结合顺序,说明f本身是一个指针。
- 如果写成返回整型指针的那种函数声明,星号修饰的是返回值,不是f这个变量本身。
函数指针的声明和调用方法
声明函数指针时,必须先明确目标函数的返回值类型和参数类型,这两部分要与被指向函数保持一致。只要类型不匹配,编译器通常就会给出警告,严重时会导致调用结果不可预期。
调用函数指针有两种常见写法,一种是直接写指针名加参数,另一种是先解引用再传参。两者在多数场景下效果相同,实际开发中通常选择更清晰的写法。
基本语法
完整示例
#include <stdio.h> int add(int a, int b) { return a + b; } int main(void) { int (*fp)(int, int) = add; int result1 = fp(3, 4); int result2 = (*fp)(5, 6); printf("result1=%dn", result1); printf("result2=%dn", result2); return 0; }- 编译命令:
cc -std=c11 demo.c -o demo
常见声明变体
不同返回值和参数形式
#include <stdio.h> void hello(void) { printf("hellon"); } int next_value(int x) { return x + 1; } int main(void) { void (*say)(void) = hello; int (*step)(int) = next_value; say(); printf("%dn", step(9)); return 0; }
用typedef简化声明
typedef示例
#include <stdio.h> typedef int (*OpFunc)(int, int); int add(int a, int b) { return a + b; } int sub(int a, int b) { return a - b; } int main(void) { OpFunc op = add; printf("%dn", op(8, 3)); op = sub; printf("%dn", op(8, 3)); return 0; }
函数指针常见使用场景
函数指针最常见的价值,不在于单独调用某个函数,而在于把要执行哪种逻辑变成可传递参数。这样可以减少大量分支判断,让程序结构更灵活。
当一个模块只关心调用规则,而不想写死具体实现时,函数指针就很适合。比如排序规则可切换、事件触发后的处理方式可替换、不同平台下的接口可统一封装。
回调函数
把函数作为参数传入
#include <stdio.h> int add(int a, int b) { return a + b; } int multiply(int a, int b) { return a * b; } int calculate(int x, int y, int (*op)(int, int)) { return op(x, y); } int main(void) { int r1 = calculate(2, 3, add); int r2 = calculate(2, 3, multiply); printf("add=%dn", r1); printf("multiply=%dn", r2); return 0; }- 这个例子里calculate只负责调用规则,真正执行加法还是乘法由传入的函数指针决定。
- 读代码时可以按顺序理解为:先声明参数op是函数指针,再在函数体内用op(x, y)完成回调调用。
状态分发
根据状态选择处理函数
#include <stdio.h> void handle_idle(void) { printf("idlen"); } void handle_run(void) { printf("runn"); } int main(void) { void (*handler)(void); int state = 1; if (state == 0) { handler = handle_idle; } else { handler = handle_run; } handler(); return 0; }- 这种写法把分支判断和真正执行动作拆开了,后续如果状态更多,可以继续扩展。
函数指针数组
命令表示例
#include <stdio.h> 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 main(void) { int (*ops[3])(int, int) = { add, sub, mul }; const char *names[3] = { "add", "sub", "mul" }; int i; for (i = 0; i < 3; i++) { printf("%s=%dn", names[i], ops[i](6, 2)); } return 0; }- int (*ops[3])(int, int)表示ops是一个数组,数组里有3个元素,每个元素都是函数指针。
- 这类结构很适合做菜单映射、简单解释器或命令分发表。
使用时容易出错的地方
初学者最常见的问题是把普通函数声明、返回指针的函数和函数指针声明混在一起。看不清括号的归属时,建议先找到变量名,再向外层分析它的类型结构。
另一个常见问题是类型不一致。返回值、参数个数、参数顺序只要有一项不同,就不应强行赋值给同一个函数指针。即使程序能编译通过,后续调用也可能产生隐蔽错误。
错误写法与正确写法
声明和赋值对照
#include <stdio.h> int add(int a, int b) { return a + b; } void print_num(int x) { printf("%dn", x); } int main(void) { int (*ok)(int, int) = add; /* int *wrong(int, int) = add; */ /* int (*bad)(int) = add; */ printf("%dn", ok(1, 2)); print_num(5); return 0; }- 把wrong写成返回整型指针的函数声明时,它并不是函数指针,所以不能拿来接收add。
- int (*bad)(int)虽然长得像函数指针,但参数列表与add不一致,依然不能正确赋值。
- 先确认返回值类型,再确认参数个数和顺序,最后再看变量名是否写成(*fp)形式。
如何快速掌握函数指针
理解函数指针的有效办法,不是死记语法,而是把它放进真实小例子里反复练习。先从声明一个指向加法函数的指针开始,再过渡到把函数作为参数传入另一个函数。
如果已经能独立读懂声明、完成赋值并正确调用,那么再学习回调和函数指针数组就会轻松很多。把每一步拆开验证,比一次记住所有变形更高效。
建议练习顺序
- 第一步:自己写出int (*fp)(int, int),再把add赋值给fp,并输出
fp(3, 4)的结果7。 - 第二步:把函数指针作为参数传给calculate这类函数,分别传入add和multiply,检查输出是否为
5和6。 - 第三步:写一个包含add、sub、mul的函数指针数组,循环调用并核对输出是否为8、4、12。
判断方法
- 每次看到复杂声明时,先找变量名,再看它是否先与*结合,最后再看参数列表和返回值。
- 如果自己无法立刻判断类型,就先写成typedef别名,再回头对照原始声明,通常会更容易理解。
函数指针并不神秘,难点主要在语法外观。只要抓住类型必须一致、变量保存函数地址、调用时按签名传参这几个核心点,再结合回调、函数指针数组和语法对照反复练习,理解和使用都会稳定很多。
相关文章
- tlwdr5660路由器怎么设置桥接(tlwdr5660路由器设置桥接方法) 09-09
- 异环和异常一起上镜成就怎么解锁怎么做-人物关系和任务条件 09-09
- 重返未来1999角色强度榜最新角色强度怎么排-强势角色和培养建议 09-09
- c语言scanf什么意思 09-09
- 异环薄荷怎么养怎么做-触发条件 09-09
- 凤翎九州阵容排行 平民最强搭配讲了什么-主要信息和内容重点 09-09