在c语言中每个类型变量都有地址,他们的地址可以存到相对应的指针变量里,称为整型指针、字符指针、数组指针,当然函数也不例外,函数的函数名实际就是这个函数的地址,这个地址也可以存到一个指针变量中在,这个指针变量称为函数指针。
例如 : int (*cmp)(int, int)
- 这就是一个函数指针 ,这个函数指针可以指向的是一个返回值为int类型,并且有两个整形参数的函数
- 对比一下返回值为int*,参数为两个整形的函数名:int* cmp(int, int); 其实就是一个括号的差别
- 对比常见的整形指针int *p,int是这个指针的类型,p是指针的名称,*号是指针的标志,*号实际与p结合,上述的函数指针也一样,int的返回值类型和两个int类型的参数是函数指针的类型,cmp是指针的名称,*号就是指针的标志,括号的意义就是让*号与cmp相结合
如何给函数指针赋值?
int (*cmp)(int, int);
int cmp_int(int a, int b);
//赋值
cmp = cmp_int;
赋值之后如何传递参数?
int ret = cmp_int(3, 5);
使用放法和函数调用相似,那这不是就和调用函数时一样的操作了吗?其实不然,在特定的情况下,函数指针的优势就会显现出来,比如,回调函数(本文后面讲解)
2.函数指针数组和定义,转移表
函数指针数组就是这个数组中的每个元素都存放着一个可以指向一个特定类型函数的指针,int类型的数组中每个元素都是int类型,那么函数指针数组中的每个指针可指向的函数类型都是一样的,即返回值类型以及参数的类型和多少都是一样的
例如:int (cmp[3])(int, int)
数组中的元素具体使用和单独一个函数指针使用的方法一致的,类比int类型和int类型的数组
int a;
a = 10;
int arr[3];
arr[0] = 5;
arr[1] = 2;
arr[2] = 20;
转移表就是函数指针数组的应用,实现状态之间的“转移”
回想一下,我们之前在使用if和switch时,一般最多只有十几二十次情况,如果还使用switch语句,函数体就会变得非常庞大,并且不易于书写,转移表的做法就是把switch的每个case的内容都封装到一个函数里,并将这些函数与函数指针数组中的每个指针关联起来,即赋值,在使用的时候直接对函数指针解引用即可
3.指向函数指针数组的指针和定义
指向函数指针数组的指针,数组的元素是指针,当这个数组的指针解引用后,还是一个指针,所以指向函数指针数组的指针是一个二级指针
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;
}
4.回调函数的使用
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
说白了,就是用别人的函数调用自己的函数。
#include<stdio.h>
void hello()
{
printf("hello world!\n");
}
int main()
{
void(*fun)(); //定义一个函数指针
fun= hello; //给函数指针赋值
fun(); //调用 hello函数
system("pause");
return 0;
}
5.练习使用qsort函数排序各种类型的数据。
qsort:
函数原型:
void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );
参数:
base:要排序的数组
num:数组元素的个数
width:每个元素的宽度,即每个元素多少个字节
compare:函数指针
使用qsort对整形数组和字符数组进行排序,代码如下:
更对qsort的使用查看链接:https://blog.youkuaiyun.com/eapid/article/details/1552310
#include<stdio.h>
#include<stdlib.h>
#include<search.h>
int qsort_int(void* x, void* y) {
int a = *((int*)x);
int b = *((int*)y);
if (a > b) {
return 1;
}
else if (a < b) {
return -1;
}
else {
return 0;
}
}
int qsort_string(void* x, void* y) {
char a = *((char*)x);
char b = *((char*)y);
if (a > b) {
return 1;
}
return -1;
}
int main()
{
int arr[] = { 5,5,7,7,3,3,4,1,77,444,234,675,6,4,3,2,5,67 };
char str[] = { 'g','x','r','d','a','b','c'};
int len_int = sizeof(arr) / sizeof(arr[0]);
int len_str = sizeof(str) / sizeof(str[0]);
qsort(arr, len_int, sizeof(int), qsort_int);
qsort(str, len_str, sizeof(char), qsort_string);
int i = 0;
printf("整形数组排序\n");
for (i=0; i < len_int; i++) {
printf("[%d] ", arr[i]);
}
printf("\n字符数组排序\n");
for (i=0; i < len_str; i++) {
printf("[%c] ", str[i]);
}
system("pause");
return 0;
}
7.模仿qsort的功能实现一个通用的冒泡排序。
#include<stdio.h>
int qsort_int(void* x, void* y) {
int a = *((int*)x);
int b = *((int*)y);
if (a > b) {
return 1;
}
else if (a < b) {
return -1;
}
else {
return 0;
}
}
void swap(void* x, void* y, int width) {
char *a = (char*)x;
char *b = (char*)y;
char box;
while (width--)
{
box = *a;
*a = *b;
*b = box;
a++, b++;
}
}
void _bubblesort(void* base, int num, int width, int(*cmp)(void *, void *)) {
char* arr = (char*)base;
int i = 0;
int j = 0;
int flag = 0;
for (; i < num; i++) {
for (j = i; j < num; j++) {
if (cmp(arr+i*width, arr+j*width) >= 0) {
swap(arr+i*width, arr+j*width, width);
}
}
}
}
int main()
{
int arr[] = { 5,5,7,7,3,3,4,1,77,444,234,675,6,4,3,2,5,67 };
int len = sizeof(arr) / sizeof(arr[0]);
_bubblesort(arr, len, sizeof(int), qsort_int);
int i = 0;
for (; i < len; i++) {
printf("[%d] ", arr[i]);
}
system("pause");
return 0;
}