C/C++高阶语法:函数指针及其应用,回调函数
2015-11-04 08:43
501 查看
1、首先了解一下回调函数的概念:
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。2、为什么要使用回调函数呢?
因为使用回调函数,在编写代码时我们可以把调用者(主调函数)与被调用者(被调函数)分开。调用者不关心谁是被调用者,所有它需知道的,只是存在一个具有某种特定原型、某些限制条件(如返回值为int)的被调用函数。这同特定原型,某些限制条件就是我们能够使用回调函数的根本。
3、回调函数在实际工程中的应用:
如果想知道回调函数在实际中有什么作用,先假设有这样一种情况,我们要编写一个库,它提供了某些排序算法的实现,如冒泡排序、快速排序、shell排序、shake排序等等,但为使库更加通用,不想在函数中嵌入排序逻辑,而让使用者来实现相应的逻辑;或者,想让库可用于多种数据类型(int、float、string),此时,该怎么办呢?可以使用函数指针,并进行回调。回调函数使用的比较多的还是基于动态链接库的调用,所以本文的例子就基于动态链接库来讲。动态链接库的知识点这里就不讲了,如果还有不知道动态链接库的,可以看在函数指针及其应用,动态链接库,正向调用 中查看动态链接库的相关应用。
4、回调函数的实际应用:
还是先看一下例子:#include <stdio.h> #include <stdlib.h> #include <string.h> #include <Windows.h> typedef char* (__stdcall *FindKey)(const char (*KeyValue)[40] /*in*/, const char *KeyBuf /*in*/); typedef int (__stdcall *TrimSpace)(const char *strInput /*in*/, char *strOut /*out*/); typedef int (*pGetKeyValue)(const char (*KeyValue)[40] /*in*/, const char *KeyBuf /*in*/, char *ValueBuf /*out*/, int * ValueLenth /*out*/,\ FindKey findKey,TrimSpace trimSpace); char *__stdcall Find_Key(const char (*KeyValue)[40] /*in*/, const char *KeyBuf /*in*/) { int i = 0; char *pFind = NULL; if (NULL == KeyValue || NULL == KeyBuf) { return NULL; } for (i = 0; i < 10; i++) { pFind = strstr(*(KeyValue + i), KeyBuf); if (NULL != pFind) { return pFind; } } return NULL; } int __stdcall Trim_Space(const char *strInput /*in*/, char *strOut /*out*/) { int i = 0; int j = 0; int nCount = 0; int ret = 0; if (NULL == strInput || NULL == strOut) { ret = -3; return ret; } j = strlen(strInput)-1; while (strInput[i] ==32) { i++; if (32 != strInput[i]) { break; } } while (strInput[j] == 32) { j--; if (32 != strInput[j]) { break; } } nCount = j - i + 1; memcpy(strOut, strInput+i, nCount); strOut[nCount] = '\0'; return ret; } int main() { const char KeyValue[10][40] = { "key1= today", "key2 = is ", "key3= a ", "key4 = very ", "key5= beautiful", "key6= and ", "key7=very", "key8= important", "key9= nice ", "key10= day " }; char KeyBuf[10] = { 0 }; char ValueBuf[40] = { 0 }; int nLenth = 0; int ret = 0; HANDLE m_handle; pGetKeyValue getKeyValue = NULL; m_handle = LoadLibrary(TEXT("Sort.dll")); if(NULL!= m_handle) { getKeyValue = (pGetKeyValue)GetProcAddress(m_handle,"GetKeyValue"); } printf("Please Input the KeyBuf:"); gets(KeyBuf); if(NULL!=getKeyValue) { ret = getKeyValue(KeyValue, KeyBuf, ValueBuf, &nLenth,Find_Key,Trim_Space); } if (0 != ret) { printf("Func_GetKeyValue_error:%d\n", ret); } printf("%s\n%s\n%d\n", KeyBuf, ValueBuf, nLenth); if(NULL != m_handle) { FreeLibrary(m_handle); } return 0; }
测试程序:
查找键 key1对应的键值为today,长度为5.
再次测试:
键beauty不存在,所以查找结果会返回一个错误。
这里讲一下上述函数实现查找的流程:
加载动态链接库:
m_handle = LoadLibrary(TEXT("Sort.dll"));
然后使用函数指针指向动态链接库中的函数:
getKeyValue = (pGetKeyValue)GetProcAddress(m_handle,"GetKeyValue");
调用动态链接库函数:这是最关键的一步。
ret = getKeyValue(KeyValue, KeyBuf, ValueBuf, &nLenth,Find_Key,Trim_Space);
然后在动态链接库中进行查找,动态链接库中需要findKey,以及 trimSpace,但是在运行的时候调用的实际上是我们自己写的函数:
char *__stdcall Find_Key(const char (*KeyValue)[40] /*in*/, const char *KeyBuf /*in*/)
int __stdcall Trim_Space(const char *strInput /*in*/, char *strOut /*out*/)
5、最后附上动态链接库的源代码:
#include "stdlib.h" #include "stdio.h" #include "string.h" typedef char* (__stdcall *FindKey)(const char (*KeyValue)[40] /*in*/, const char *KeyBuf /*in*/); typedef int (__stdcall *TrimSpace)(const char *strInput /*in*/, char *strOut /*out*/); __declspec(dllexport) int GetKeyValue(const char (*KeyValue)[40] /*in*/, const char *KeyBuf /*in*/, char *ValueBuf /*out*/, int * ValueLenth /*out*/,\ FindKey findKey,TrimSpace trimSpace) /* keyValue 输入的键值表 ****keyBuf 输入的键 ****valueBuf 输出键对应的键值 ****valueLenth 输出键值的长度 ****findKey 查找键的函数 ****trimSpace 去掉键值中包含的空格 */ { int j = 0,i=0; int ret = 0; int nCount = 0; char *pFindKey = NULL; char *strSource = NULL; char strReturn[40] = { 0 }; if (NULL == KeyValue || NULL == KeyBuf || NULL == ValueBuf || NULL == ValueLenth) { ret = -1; return ret; } strSource = ValueBuf; pFindKey = findKey(KeyValue, KeyBuf); if (NULL == pFindKey) { ret = -2; return ret; } j = strlen(pFindKey); for (i = 0; i < j; i++) { if (61 == pFindKey[i]) break; } pFindKey = pFindKey + i+1; ret = trimSpace(pFindKey, strReturn); if (ret != 0) { return ret; } nCount = strlen(strReturn); strSource = strReturn; while ((*ValueBuf++ = *strSource++) != '\0'); ValueBuf[nCount] = '\0'; *ValueLenth = nCount; return ret; }我们可以看到,在动态链接库中并没有对trim_Space和find_Key进行定义,这也是能够实现回调的一个重要原因。
相关文章推荐
- ——黑马程序员——C语言中构造类型—结构体(二)
- c++ read
- 在Windows平台搭建C语言开发环境的多种方式
- C++除法实现方式及负数取模
- 对字符串中的字符进行统计
- c++11特性之std::thread--进阶二
- c++11特性之std::thread--进阶二
- leetcode笔记:House Robber II
- 高质量程序设计指南C++/c语言 第四章
- [转]VC++中CTime类Format参数详解
- c++11特性之std::thread--进阶
- c++11特性之std::thread--进阶
- C++搜索引擎—Xapian中文简介
- C++: 类(class) 随笔
- c++初始化列表
- C语言:判断一个字符串是否为另外一个字符串旋转之后的字符串。(左旋右旋、求子串)
- C语言:实现一个函数,可以左旋字符串中的k个字符。
- C语言:每瓶汽水1元,两个空瓶可以置换一瓶汽水,现在有20元,最多能喝多少瓶汽水。
- C语言中的中文处理的问题。
- Char, String 和 Byte 等类型间的转换和编码