一、什么是回调函数
回调函数,个人理解,就是把函数指针作为函数参数用于传参,这个函数指针指向的函数就叫做回调函数。
二、为什么要使用回调函数
换句话说,使用回调函数有什么好处,个人理解,可以更灵活得处理同一类事件中的不同情况,但也有一些通用的地方。
下面我们来举个例子说明:
我们要打印清华大学计算机学院 老师和学生的信息,老师和学生所属学校和学院是一样的,但身份却不一样,这个时候我们就可以用回调函数来实现了。
示例代码
#include <stdio.h>
void print_student(void)
{
printf("学生\n");
}
void print_teacher(void)
{
printf("老师\n");
}
void print_info(void(*call_back)(void))
{
call_back();
printf("清华大学\n");
printf("计算机学院\n");
printf("\r\n");
}
int main(void)
{
print_info(print_student);
print_info(print_teacher);
return 0;
}
运行结果:
其中 void print_student(void) 和 void print_teacher(void) 就是回调函数了
将通用功能放在 void print_info(void(*call_back)(void)) 中实现,差异性功能放在回调函数中处理。
如果我们希望老师和学生和信息更加详细,希望知道他们的年龄和姓名呢,那就需要给回调函数传参了
示例代码
#include <stdio.h>
void print_student(char *name, int age)
{
printf("身份:学生\n");
printf("姓名:%s\n", name);
printf("年龄:%d\n", age);
}
void print_teacher(char* name, int age)
{
printf("身份:老师\n");
printf("姓名:%s\n", name);
printf("年龄:%d\n", age);
}
void print_info(void(*call_back)(char*, int), char *name, int age)
{
call_back(name, age);
printf("学校:清华大学\n");
printf("学院:计算机学院\n");
printf("\r\n");
}
int main(void)
{
print_info(print_student,"小明", 20);
print_info(print_teacher, "李教授", 30);
return 0;
}
运行结果:
当然如果还需要更多的信息时,我们可以定义结构体来作为回调函数的参数进行传参。
三、工程项目中的回调函数
sqlite 是一个开源的嵌入式关系数据库,实现自包容、零配置、支持事务的SQL数据库引擎。
在 sqlite 中就用到了回调函数
示例代码
以下代码摘自 《sqlite 菜鸟教程》
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
static int callback(void *NotUsed, int argc, char **argv, char **azColName){
int i;
for(i=0; i<argc; i++){
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("\n");
return 0;
}
int main(int argc, char* argv[])
{
sqlite3 *db;
char *zErrMsg = 0;
int rc;
char *sql;
/* Open database */
rc = sqlite3_open("test.db", &db);
if( rc ){
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
exit(0);
}else{
fprintf(stdout, "Opened database successfully\n");
}
/* Create SQL statement */
sql = "CREATE TABLE COMPANY(" \
"ID INT PRIMARY KEY NOT NULL," \
"NAME TEXT NOT NULL," \
"AGE INT NOT NULL," \
"ADDRESS CHAR(50)," \
"SALARY REAL );";
/* Execute SQL statement */
rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
if( rc != SQLITE_OK ){
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}else{
fprintf(stdout, "Table created successfully\n");
}
sqlite3_close(db);
return 0;
}
上面代码实现了创建数据库的功能。
在 sqlite3_exec 函数中用到了回调函数,因为不同的 sql 语句返回的内容会不一样,而数据库对 sql 语句的执行步骤又是一样的,所以将返回的内容放到回调函数中操作是非常好的选择。
四、回调函数的好处
可以使程序更加 简洁,提高代码复用率
可以使程序代码 结构更加清晰,更好地展示行为的多种形态
使程序代码的编写和处理更加 灵活