文章目錄
- 前言
- 一、回調函數是什么
- 二、回調函數的使用
- 1.使用標準庫中的qsort函數
- 2.利用qsort函數對結構體數組進行排序
- 三、實現qsort函數
- 總結
先記錄一下訪問量突破2000啦,謝謝大家支持!!!
這里是上期指針進階鏈接,方便大家查看:添加鏈接描述
前言
大家好呀,今天分享一下上期指針進階中剩余的內容——回調函數,這個很重要滴,讓我們一起來學會學懂他吧!!!
一、回調函數是什么
標準概念:
回調函數就是一個通過函數指針調用的函數。如果你把函數的指針(地址)作為參數傳遞給另一個
函數,當這個指針被用來調用其所指向的函數時,我們就說這是回調函數。回調函數不是由該函數
的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用于對該事件或條件進
行響應。
簡單來說就是:在另一個函數中利用函數指針調用的函數叫做回調函數
二、回調函數的使用
1.使用標準庫中的qsort函數
qsort函數不僅可以排序整型數組,還可以排序結構體等數據類型
代碼如下:
#include <stdio.h>
//qosrt函數的使用者得實現一個比較函數
int int_cmp(const void * p1, const void * p2)
{return (*( int *)p1 - *(int *) p2);
}//這里必須有使用者根據自己的排序依據自己寫的比較函數int main()
{int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };int i = 0;qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);//qsort的第一個參數是排序數組的首元素地址//第二個參數是排序的長度//第三個參數是每個元素的大小//第四參數是使用者自己寫的排序依據函數的地址(這里就是使用回調函數)for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++){printf( "%d ", arr[i]);}printf("\n");return 0;
}
整型數組排序的運行結果展示:
2.利用qsort函數對結構體數組進行排序
先看代碼如下:
#include<stdio.h>
#inlcude<string.h>
struct stu {int age;char name[20];double score;
};
//依據年齡大小排序的比較函數
int compar_by_age(const void* e1, const void* e2)
{return ((struct stu*)e1)->age - ((struct stu*)e2)->age;
}
//依據名字排序的比較函數
int compar_by_name(const void* e1, const void* e2)
{return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
}
int main()
{
//這是定義一個結構體類型的數組struct stu S[3] = { {21,"FRH",100},{19,"MSY",90},{18,"LZY",85} };int Ssz = sizeof(S) / sizeof(S[0]);qsort(S, Ssz, sizeof(S[0]), compar_by_age);qsort(S, Ssz, sizeof(S[0]), compar_by_name);return 0;
}
排序前后結果對比:
這是排序前結構體數組的順序:
這是按照年齡排序后的順序:
這是按照姓名排序后的順序:
三、實現qsort函數
我們先來看一下qsort函數在標準庫中的模樣:
他沒有返回值,四個參數分別是:
1、qsort的第一個參數是排序數組的首元素地址
2、第二個參數是排序的長度
3、第三個參數是每個元素的大小
4、第四參數是使用者自己寫的排序依據函數的地址(這里就是使用回調函數)
作者是依據冒泡排序實現的qosrt函數,我們之間上代碼:
#include<stdio.h>
#inlcude<string.h>
//依據名字排序的比較函數
int compar_by_name(const void* e1, const void* e2)
{return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
}
//依據整型大小排序的比較函數
int int_cmp(const void * p1, const void * p2)
{//這里都會將接收到的地址轉換為所需要比較的類型return (*( int *)p1 - *(int *) p2);
}//這里排序中交換兩個元素的交換函數
void Swap(char* x, char* y,int size)
{
//利用char* 接收需要交換的元素,可以保證對其每個字節進行交換從而實現整體全部字節的交換
//size就是該元素所占字節的大小,決定每次交換循環幾次int i = 0;for (i = 0; i < size; i++){char temp = *x;*x = *y;*y = temp;x++;y++;}
}void Bubble_Sort(void* base, size_t num, size_t size,int (*compar)(const void*, const void*))
{int i = 0;for (i = 0; i < num - 1; i++){int j = 0;for (j = 0; j < num - 1 - i; j++){//為什么要將首元素地址轉換為char* 類型呢?//因為:這樣可以保證任何類型數組在排序比較時能夠訪問到其中的每一個元素//這個設計是真的巧妙if (compar(((char*)base + j * size), ((char*)base + (j+1)*size))>0){Swap(((char*)base + j * size), ((char*)base + (j+1)*size), size);}}}
}
對其進行測試:
int main()
{int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };struct stu S[3] = { {21,"FRH",100},{19,"MSY",90},{18,"LZY",85} };int Ssz = sizeof(S) / sizeof(S[0]);int sz = sizeof(arr) / sizeof(arr[0]);Bubble_Sort(arr,sz,sizeof(arr[0]),compar_by_int);Print(arr, sz);Bubble_Sort(S, Ssz, sizeof(S[0]), compar_by_age);Bubble_Sort(S, Ssz, sizeof(S[0]), compar_by_name);return 0;
}
可以得到,排序結果和上面調用標注庫中qsort函數的結果是相同的
總結
關于回調函數的分享就到這里啦,希望qsort函數可以幫助到大家,博主感覺他真的是很有用,以后會盡量使用到他的,希望本篇文章可以幫助到大家,謝謝大家閱讀!!!