一、函数指针与指针函数
函数指针与指针函数这是大家经常会遇见的一个问题,很容易混淆,我们可以从字面上来理解二者的含义:
1、指针函数
指针函数本质上是描述它是一个函数,只是函数的返回值类型是指针。
如下面的这个函数get_memory()将返回一个指针,那它就是一个指针函数。
char *get_memory(int size);
{
return (char *)malloc(size);
}
2、函数指针
函数指针本质上是描述它是一个指针,只不过这个指针的类型是函数。
那什么是函数指针呢?首先,函数名就是函数的入口地址,既然它是一个地址,那就可以用一个指针来指向它。这样,指向函数的指针就是函数指针 。那么函数指针该如何定义、如何使用呢?
下面我们先用一个例子来简单演示一下:
#include <stdio.h>
int add(int a,int b)
{
return a+b;
}
int main(int argc,char *argv[])
{
int (*ptr)(int,int); //定义了一个函数指针ptr,接下来详细讲解为什么这样定义
ptr = add; //让指针ptr指向函数add()
printf("result:%d\n",add(111,555)); //add就是add()函数的入口地址,如果要调用该函数应该这样调用
printf("result:%d\n",ptr(111,555)); //ptr也是add()函数的入口地址,所以它的调用方式应该跟add()一样
return 0;
}
运行结果:
3、函数指针的定义
在main()函数的入口处,我们定义了一个ptr函数指针。那函数指针是如何定义的呢?能不能定义成别的样子呢?接下来让我们一起来看看:
int var //这里我们定义了一个int类型的变量,那么我们该如何定义一个指针
指向它呢?
int *ptr //应该这么定义,将var换成*ptr即可
int *var //这里我们定义了一个int类型的指针变量,那我们该如何定义一个指针
指向它的?
int **ptr //应该这么定义,即把var换成*ptr即可
struct struct_type var //这里我们定义了一个struct struct_type类型的变量,那我
们又该如何定义一个指针指向它呢?
struct struct_type *ptr //应该这么定义,即把var换成*ptr即可
int func(int a,int b) //如果这里是一个函数,那么该如何定义?
int *ptr (int a,int b) //应该这么定义,即把var换成*ptr即可吗?
/*
如果只是这样简单地替换,我们再仔细看看上面的代码:该语句是一条声明语句,
它声明了一个函数ptr()。该函数有一个int *类型的返回值有两个int类型长度参数
a和b,而并不是我们想要的定义一个函数指针ptr。之所以出现这个问题,这是因为
前面的*与int结合了,表示它的返回值是int *类型。如果想要说明它是一个指针,那
应该让*与ptr结合,而不是与int结合。这时加上一个括号即可。
*/
//所以正确定义函数指针的方式应该是这样的,通过(*ptr)改变了这里*的本质
int (*ptr)(int a,int b)
/*
那又该如何解读这个函数指针的定义呢?
1.()使得*与ptr结合,说明ptr是一个指针
2.前面的int说明该指针指向的函数要有一个int类型的返回值
3.后面的(int a,int b)说明该指针指向的函数要有两个int类型的参数
4.事实上,函数就是对输入的数据进行处理,并返回相应的结果。所以对于函数而言,
我们也只需要关心它的输入参数和返回值
5.由此可以看出,对于ptr指针而言,只要返回值为int并且有两个int类型参数的函数
都可以指向。
*/
//经过上面的学习,叫我们看看下面的两个例子
int *swap(int *a,int *b) //定义一个这样的函数,那它的函数指针该怎么写?
->>>int *(*ptr) (int *a,int *b)
int *(*ptr)(int,int *,char **) //定义一个这样的函数,那它的函数指针该怎么写?
->>>int *func(int,int *,char **)
在这里,我们定义函数指针的时候,定义的语句会很长,代码也不容易看懂,此时我们可以使用typedef关键字来定义一种函数指针类型,从而简化代码,如下图所示:
typedef int int_t //这里使用typedef构造了一个新的类型int_t,事实上它就是int类型
typedef int * int_ptr_t //这里使用typedef构造一个int_ptr_t,事实上它就是int *类型
int func(int a,int b) //这里定义了一个函数,那如何定义一种类型指向这个函数呢
typedef int (func_ptr_t *)(int a,int b) //将func替换成(func_ptr_t *)并在前面
加上typedef关键字,此时即定义了一个新的函数指针类型
func_ptr_t ptr = func //这时,我们用新的类型func_ptr_t定义了一个函数指针
ptr,并让ptr指向func函数
二、函数指针使用
通过上面的学习,应该对函数指针有了初步的了解,那我们具体看看函数指针的一些用法吧!
1、函数指针的声明
函数指针的声明形式如下:
return_type (*pointer_name) (parameter_types);
return_type
是函数的返回类型。pointer_name
是指针变量的名称。parameter_types
是函数的参数类型。
例如:int (*add)(int, int);
2、函数指针的赋值
可以将函数的地址赋值给函数指针。注意函数名本身就是一个指向函数的指针。
#include <stdio.h>
int add(int a, int b) {
return a + b;
}
int main() {
int (*sum_ptr)(int, int); // 声明一个函数指针
sum_ptr = add; // 将函数的地址赋值给指针
// 通过函数指针调用函数
int result = sum_ptr(3, 4);
printf("Result: %d\n", result); // 输出:Result: 7
return 0;
}
3、使用typedef简化函数指针的声明
通过 typedef
可以简化函数指针的声明,提高代码的可读性。
#include <stdio.h>
typedef int (*SumFunction)(int, int);
int add(int a, int b) {
return a + b;
}
int main() {
SumFunction sum_ptr = add; // 使用 typedef 声明函数指针
int result = sum_ptr(3, 4);
printf("Result: %d\n", result);
return 0;
}
4、函数指针作为参数
函数指针可以作为函数的参数,这样可以传递不同的函数给同一个函数进行处理。
#include <stdio.h>
int add(int a, int b) {
return a + b;
}
int subtract(int a, int b) {
return a - b;
}
int calculate(int (*operation)(int, int), int x, int y) {
return operation(x, y);
}
int main() {
printf("Addition result: %d\n", calculate(add, 5, 3)); // 输出:Addition result: 8
printf("Subtraction result: %d\n", calculate(subtract, 5, 3)); // 输出:Subtraction result: 2
return 0;
}
5、函数指针数组
可以创建函数指针数组,用于存储不同函数的地址。
#include <stdio.h>
int add(int a, int b) {
return a + b;
}
int subtract(int a, int b) {
return a - b;
}
int multiply(int a, int b) {
return a * b;
}
int main() {
int (*operations[3])(int, int) = {add, subtract, multiply};
printf("Addition result: %d\n", operations[0](5, 3)); // 输出:Addition result: 8
printf("Subtraction result: %d\n", operations[1](5, 3)); // 输出:Subtraction result: 2
printf("Multiplication result: %d\n", operations[2](5, 3)); // 输出:Multiplication result: 15
return 0;
}
三、回调函数
回调函数(Callback Function)指的是将一个函数作为参数传递给另一个函数,并在后者执行过程中调用前者。函数指针和回调函数之间存在密切的关系。在 C 语言中,回调函数通常通过函数指针来实现。
下面是一个简单的示例,演示了回调函数的用法:
#include <stdio.h>
// 回调函数的定义,用于处理数组中的每个元素
typedef void (*CallbackFunction)(int);
// 函数,接受一个数组和数组的大小,以及一个回调函数
void processArray(int arr[], int size, CallbackFunction callback) {
for (int i = 0; i < size; ++i) {
// 在适当的时候调用回调函数
callback(arr[i]);
}
}
// 回调函数的具体实现,用于打印每个元素的平方
void printSquare(int num) {
printf("%d ", num * num);
}
int main() {
int numbers[] = {1, 2, 3, 4, 5};
int size = sizeof(numbers) / sizeof(numbers[0]);
// 调用 processArray 函数,并传递 printSquare 函数作为回调
processArray(numbers, size, printSquare); // 输出:1 4 9 16 25
return 0;
}