一、函数指针
先看一段代码:
#include <stdio.h>
void test()
{
printf("hehe\n");
}
int main()
{
printf("%p\n", test);
printf("%p\n", &test);
return 0;
}
结果如下:
输出的是两个地址,这两个地址是test 函数的地址。 那我们的函数的地址要想保存起来,怎么保存?
下面我们看代码:
void test()
{
printf("hehe\n");
}
//下面pfun1和pfun2哪个有能力存放test函数的地址?
void (*pfun1)();
void *pfun2();
首先,能给存储地址,就要求pfun1或者pfun2是指针,那哪个是指针? 答案是:
#include <stdio.h>
int Add(int a, int b) {
return a + b;
}
int main()
{
printf("%d\n", Add(2,3));
return 0;
}
看上边代码以前调用函数就是函数名(实参列表)。但是还可以用指针调用。
改写上边的代码:
#include <stdio.h>
int Add(int a, int b) {
return a + b;
}
int main()
{
printf("%d\n", Add(2,3));
int (*p)(int, int) = Add;
printf("%d\n", (*p)(20, 30));
}
Add是函数代码快的首地址,让指针p指向该函数的首地址。指针调用函数也能完成功能。
对于函数Add其函数名代表的是函数的起始地址和&Add函数地址两者等价
二、 函数指针数组
数组是一个存放相同类型数据的存储空间,那我们已经学习了指针数组, 比如:
那要把函数的地址存到一个数组中,那这个数组就叫函数指针数组,那函数指针的数组如何定义呢?
int (*parr1[10])();
答案是:parr1 parr1 先和[] 结合,说明parr1是数组,数组的内容是什么呢? 是int (*)() 类型的函数指针。
函数指针数组的用途:转移表
基于函数指针的简易计算器:
#include <stdio.h>
#include<iostream>
using namespace std;
#pragma warning(disable:4996)
int Add(int a, int b) {
return a + b;
}
int Mul(int a, int b) {
return a - b;
}
int Ch(int a, int b) {
return a * b;
}
int Div(int a, int b) {
return a / b;
}
void mun() {
cout << "***************" << endl;
cout << "1 加法 2 减法 " << endl;
cout << "3 乘法 4 除法 " << endl;
cout << "***************" << endl;
}
int main() {
int i;
int (*p[5])(int, int) = { NULL,Add,Mul ,Ch,Div };//将函数指针数组中的每个函数指针指向四个函数。
int b, c;
while (1) {
mun();
cout << "输入运算种类" << endl;
cin >> i;
cout << "输入操作数" << endl;
cin >> b >> c;
int a = p[i](b, c);
cout << "答案:" << a << endl;
}
return 0;
}
三、函数指针 数组指针
指向函数指针数组的指针是一个指针 指针指向一个数组,数组的元素都是函数指针;
如何定义?
void test(const char* str)
{
printf("%s\n", str);
}
int main()
{
//函数指针pfun
void (*pfun)(const char*) = test;
//函数指针的数组pfunArr
void (*pfunArr[5])(const char* str);
pfunArr[0] = test;
//指向函数指针数组pfunArr的指针ppfunArr
void (*(*ppfunArr)[10])(const char*) = &pfunArr;
return 0;
}
四、回调函数
简单看一下qsort参数
参数4是一个函数指针,qsort是一个无类型排序,要排序数组的类型由用户决定,计算机无需知道类型,只需用户实现比较大小的compar函数,函数qsort只需根据函数返回值来排序。
#include<iostream>
using namespace std;
int comint(const void* qa,const void *qb) {
int* a = (int*)qa;
int* b = (int*)qb;
if (*a > *b) {
return 1;
}else if (*a < *b) {
return -1;
}
else {
return 0;
}
}
int main() {
int arr[] = { 100,4,8,1,0,2,41,5,4,5,74,52,4,5,45,4,5,4,55,78,74 };
int num = sizeof(arr) / sizeof(arr[0]);
qsort(arr, num, sizeof(int), comint);
return 0;
}
这是对int数组进行排序,用户只需对int类型数据比较大小,并返回相应的数据
int comchar(const void* qa, const void* qb) {
char* s = *(char**)qa;
char *ss= *(char**)qb;//取字符串的地址
return strcmp(s, ss);
}
int main() {
const char* arr[] = { "abcfg","jdisai","gdhsahuj","jkhjh" };
int num = sizeof(arr) / sizeof(arr[0]);
qsort(arr, num, sizeof(char*), comchar);
}
在对字符串数组排序时,compare是获取对应字符串的地址,只要交换他们的地址就行并不需要交换内容。
使用回调函数,模拟实现qsort(采用冒泡的方式)。
int comchar(const void* qa, const void* qb) {
char* s = *(char**)qa;
char *ss= *(char**)qb;//取字符串的地址
return strcmp(s, ss);
}
void Swap( char* a, char* b,int size) {
while (size) {
char temp = *a;
*a = *b;
temp = *b;
size--;
a++;
b++;
}
}
void my_qsort(void* base, size_t num, size_t size, int (*compar)(const void*, const void*)) {
assert(base != NULL);
char* e = (char*)base;
for (int i = 0;i < num - 1;i++) {
int flag = 0;
for (int j = 0;j < num - 1 - i;j++) {
if (comchar(e + j * size, e + j * size + size)>0) {
flag = 1;
Swap(e + j * size, e + j * size + size,size);
}
}
if (flag == 0) {
break;
}
}
}
int main() {
const char* arr[] = { "abcfg","jdisai","gdhsahuj","jkhjh" };
int num = sizeof(arr) / sizeof(arr[0]);
my_qsort(arr, num, sizeof(char*), comchar);
}