文章目錄
- ? 指向函數指針數組的指針
- 📌指向函數指針數組的指針的定義
- 📌指向函數指針數組的數組指針的使用
- ?回調函數
- 📌 回調函數的定義
- 📌 回調函數的使用
- ?qsort函數
- 📌 qsort函數的作用
- 📌qsort函數的定義
- 📌qsort函數的頭文件
- 📌1.qsort函數排序整型數組
- 比較函數compare
- 主函數
- 📌2.qsort函數排列結構體數據
- 【1】排列結構體中的整型類型
- 比較函數
- 主函數以及結構體
- 【2】排列結構體中的字符串類型
- 比較函數compare
- 主函數
- 【3】 排列結構體中的浮點型數據
- 比較函數compare
- 主函數
- 📌3.qsort函數排列字符數組類型數據
- 比較函數compare
- 主函數
- ?使用回調函數,模擬實現qsort(采用冒泡的方式)
- 冒泡排序(傳送門在此[冒泡排序](https://blog.csdn.net/yyqzjw/article/details/131909947?spm=1001.2014.3001.5501))
- 模擬實現qsort排整型數組(利用冒泡排序方式)
- 總結
? 指向函數指針數組的指針
指向函數指針數組的指針是一個 指針, 指針指向一個 數組 ,數組的元素都是 函數指針 ;
如何定義?
📌指向函數指針數組的指針的定義
我們可以先定義五個函數
int add(int a, int b)
{return a + b;}
int sub(int a, int b)
{return a - b;
}
int mul(int a, int b)
{return a*b;
}
int div(int a, int b)
{return a / b;
}
分別計算兩個變量的加減乘除,然后定義一個函數指針數組用來存放上面4個函數的地址
int(*p[5])(int x, int y) = { 0, add, sub, mul, div };
空出來一個是為了讓加減乘除函數與下標對應上
int (*(*pp)[5])(int x,int y) = &p;
這個是指向函數指針數組的數組指針,ta指向的函數指針數組的類型是去掉*pp
int (*()[5])(int x,int y)
這個類型說明數組指針指向的是數組長度是5,每個元素都是地址,每個元素的類型是
int ()(int x,int y)
畫圖說明一下關系
📌指向函數指針數組的數組指針的使用
怎么通過這個數組指針pp去使用加減乘除這幾個函數呢???代碼如下
int add(int a, int b)
{return a + b;}
int sub(int a, int b)
{return a - b;
}
int mul(int a, int b)
{return a * b;
}
int div(int a, int b)
{return a / b;
}
int main()
{int(*p[5])(int x, int y) = { 0, add, sub, mul, div };int (*(*pp)[5])(int x, int y) = &p;int ret = (*(*pp + 1))(3, 4);printf("%d", ret);
}
在這塊解釋一下子
(*(*pp + 1))(3, 4)
pp存放的是p[]整個數組的地址,*pp相當于拿到這個數組,也相當于拿到數組的數組名,相當于數組首元素地址,*pp+1為第二個元素地址, 如果在對其解引用得到的是 *(pp+1),這個就是數組第二個元素的內容,也就是說add的地址,因為&add和add打印的結果一樣,使用該函數計算3+4;
add(3,4)等價 ((*pp + 1))(3, 4)
?回調函數
📌 回調函數的定義
回調函數pp()就是一個通過函數指針void(*p)()調用的函數。如果你把函數的指針(地址)作為參數傳遞給另一個函數print(&pp);,當這個指針被用來調用其所指向的函數時pp(),我們就說這是回調函數。回調函數不是由該函數的實現方直接調用,而是在if (1)特定的事件或條件發生時由另外的一方調用的,用于對該事件或
條件進行響應。
📌 回調函數的使用
void pp()
{printf("hahahahaha\n");
}
void print(void(*p)())
{if (1){p();}
}
int main()
{ print(&pp);return 0;
}
根據回調函數的定義,可知pp()函數就是回調函數。
?qsort函數
📌 qsort函數的作用
我們之前學過的冒泡排序,可以將一個整型數組排好序,如果讓我們去排序浮點型,字符型,結構體型,我們應該怎么辦呢
qsort函數可以解決這個問題,萬物皆可排。那誰誰你怎么插隊呢快去排隊
📌qsort函數的定義
在msdn上找到定義,我們可以將定義復制過來
void qsort( void *base,size_t num,size_t width,int (__cdecl *compare )(const void *elem1, const void *elem2 ) );
什么???英格力士
下面有請過英語四級的小張同學給翻譯翻譯哈哈哈哈哈
咳咳,我來了
🚫1.base指針指向的是要排序數組的首地址,因為不清楚要排序的是什么類型的數據,這里用void 可以接收任何類型的指針
2.num是該數組的元素個數
3.width是每個元素的字節大小
4.自定義比較函數compare
第四個位置是一個函數指針來接收一個比較函數的地址,參數用兩個指針接收要比較兩個元素的地址,因為不知道比較什么類型的數據,就用void的指針接收,比較函數是根據你自己要排列的數據類型自己定義的。
第一個元素大于第二個元素返回大于0的,小于第二個元素返回小于0,等于返回0
📌qsort函數的頭文件
📌1.qsort函數排序整型數組
比較函數compare
int int_cmp(const void* p1, const void* p2)
{return (*(int*)p1 - *(int*)p2);
}
這里要排整型數據,將void的指針強制類型轉化為int,一次可以訪問4個字節 ,解引用也可以得到一個整型數據
主函數
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);for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%d ", arr[i]);}printf("\n");return 0;
}
注意:如果要排成降序只需要將比較函數中的
int int_cmp(const void* p1, const void* p2)
{
return ((int)p2 - (int)p1);
}
📌2.qsort函數排列結構體數據
【1】排列結構體中的整型類型
比較函數
int int_cmp_age(const void* p1, const void* p2)//按年齡比較
{return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}
主函數以及結構體
struct Stu {char name[20];int age;float score;
};
int main()
{int i = 0;struct Stu arr[3] = {{"zhangjiawang",18,100},{"zhumiao",50,76},{"liuliu",19,76}};int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr,sz, sizeof(arr[0]), int_cmp_age);for (int i = 0; i < 3; i++){printf("%d ", arr[i].age);}return 0;
}
運行結果
【2】排列結構體中的字符串類型
比較函數compare
int int_cmp_age(const void* p1, const void* p2)
{return (strcmp(((struct Stu*)p1)->name), ((struct Stu*)p2)->name);
}
字符串比較用strcmp函數,記得添加頭文件string.h
這個是strcmp函數的返回值,和比較函數剛好對應上
主函數
int main()
{int i = 0;struct Stu arr[3] = {{"zhangjiawang",18,100},{"zhumiao",50,76},{"liuliu",19,76}};int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr,sz, sizeof(arr[0]), int_cmp_age);for (int i = 0; i < 3; i++){printf("%s ", arr[i].name);}return 0;
}
運行結果
【3】 排列結構體中的浮點型數據
比較函數compare
int int_cmp_float(const void* p1, const void* p2)
{return (*(float*)p1 -*(float*)p2);
}
主函數
int main()
{int i = 0;struct Stu arr[3] = {{"zhangjiawang",18,100.0},{"zhumiao",50,76.0},{"liuliu",19,77.0}};int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr,sz, sizeof(arr[0]), int_cmp_float);for (int i = 0; i < 3; i++){printf("%.1f ", arr[i].score);}return 0;
}
運行結果:
📌3.qsort函數排列字符數組類型數據
比較函數compare
int int_cmp(const void* p1, const void* p2)
{return (*(char*)p1 - *(char*)p2);
}
主函數
int main()
{char arr[] = {'b','c','a','f','z','q'};int i = 0;qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(char), int_cmp);for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%c ", arr[i]);}printf("\n");return 0;
}
運行結果
?使用回調函數,模擬實現qsort(采用冒泡的方式)
冒泡排序(傳送門在此冒泡排序)
int main()
{int arr[10] = {10,9,8,7,6,5,4,3,2,1};int sz = sizeof(arr) / sizeof(arr[0]);//數組長度int i;for (i = 0; i < sz - 1; i++)//趟數{int j = 0;for (j = 0; j < sz - 1 - i; j++)//比較次數{if (arr[j] > arr[j + 1])//前面大于后面,交換{int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}for (i = 0; i < sz; i++)//打印數組{printf("%d ", arr[i]);}
}
模擬實現qsort排整型數組(利用冒泡排序方式)
主函數
int main()
{int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };int i = 0;bubble_qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%d ", arr[i]);}printf("\n");return 0;
}
模擬qsort函數
將冒泡排序的實現copy過來,然后對其修改
大概替換的思想是
`void bubble_sort(void* base, int num, int width, int cmp)
{int i;
for (i = 0; i < num - 1; i++)
{
int j = 0;
for (j = 0; j < num - 1 - i; j++)
{
if (比較函數的返回值)
{交換數組元素的函數}
}
}
}
比較函數compare(這里因為要排的是整型數組,用上面整型數組的比較函數就行)
int cmp(const void* p1, const void* p2)
{
return ((int)p1 - (int)p2);
}
現在的問題是怎么使用bubble_sort函數的參數找到要比較兩個元素的地址??
代碼:
cmp((char*)base+j*width),(char*)base+(j+1)*width)>0
問題1:為什么要將base地址存在char的指針中?
方便訪問任意類型數據,因為width是一個元素的字節大小,如果訪問一個整型的地址,width就是4,char的指針+4剛好跳過4個字節,如果把base地址用int*接收,如果width還是4的話,+4就跳過的不是一個元素,而是4個元素,相鄰的元素根本就比不了大小。
如果j=0的話,上面傳到比較函數中的就是第一個元素地址和第二個元素地址
替換后的bubble_sort
void bubble_sort(void* base, int num, int width, int cmp)
{int i;for (i = 0; i < num - 1; i++){int j = 0;for (j = 0; j < num - 1 - i; j++){if (cmp((char*)base + j * width), (char*)base + (j + 1) * width) > 0){交換數組元素的函數}}}}
}
現在的問題是怎么交換兩個地址上的元素。交換數組元素的函數👇
void swap(char* p1, char* p2, int width)
{int i = 0;for (i = 0; i < width; i++){char tmp = *p1;*p1 = *p2;*p2 = tmp;p1++;p2++;}
}
這里的交換函數是按字節交換的,比如說數組前兩個元素1,3,假如說內存為小端存儲,實現前兩個元素交換
替換后的bubble_sort
void bubble_sort(void* base, int num, int width, int cmp)
{int i;for (i = 0; i < num - 1; i++){int j = 0;for (j = 0; j < num - 1 - i; j++){if (cmp((char*)base + j * width), (char*)base + (j + 1) * width)> 0){swap((char*)base + j * width), (char*)base + (j + 1) * width));}}}}
}
整體代碼展示
`#include <stdio.h>
int cmp(const void* p1, const void* p2)
{return (*(int*)p1 - *(int*)p2);
}
void swap(char* p1, char* p2, int width)
{int i = 0;for (i = 0; i < width; i++){char tmp = *p1;*p1 = *p2;*p2 = tmp;p1++;p2++;}
}
void bubble_sort(void* base, int num, int width, int cmp(const void* p1, const void* p2))
{int i;for (i = 0; i < num - 1; i++){int j = 0;for (j = 0; j < num - 1 - i; j++){if (cmp((char*)base + j * width, (char*)base + (j + 1) * width)> 0){swap((char*)base + j * width,(char*)base + (j + 1) * width,width);}}}}
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), cmp);for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%d ", arr[i]);}printf("\n");return 0;
}`
總結
希望這篇文章可以給你帶來幫助,如果有不對的地方,或者有哪里不理解的地方,請私信我,謝謝大家支持,下篇見,以上