個人主頁(找往期文章包括但不限于本期文章中不懂的知識點):?我要學編程(?_?)-CSDN博客
目錄
回調函數
qsort使用舉例
使用qsort函數排序整型數據?
使用qsort排序結構數據?
qsort函數的模擬實現?
?
回調函數
回調函數就是一個通過函數指針調用的函數。 如果你把函數指針(地址)作為參數傳遞給另?個函數,當這個指針被用來調用其所指向的函數時,被調用的函數就是回調函數。回調函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用于對該事件或條件進行響應。
簡單來說就是:當我擁有一個函數(地址)指針時,在一些特定的情況下,通過函數指針回過頭來調用這個函數,那么這個被調用的函數就是回調函數。
在簡易計算器的制作(函數指針數組的實踐)-CSDN博客這篇文章中寫的計算代碼,就是可以用這個回調函數的例子。如果我們要使用加法計算兩個數的值,不是直接由main函調用的,而是由calc函數來調用對應的加法函數。這便是回調函數。
qsort使用舉例
使用qsort函數排序整型數據?
如果我們想要排序一組數據,按照升序或者降序的方式,首先想到的就是冒泡排序。這個排序在深入解剖指針篇(2)-CSDN博客?這篇文章中介紹了。核心思想就是:兩兩相鄰元素的比較。
我們現在就用qsort函數來實現。首先,就得了解什么是qsort函數。
上面就是關于qsort函數的基本介紹。
void qsort(void* base, //這個base就是要排序的元素的起始地址size_t num, //這個num就是要排序的元素個數size_t size,//這個size就是要排序的元素對應字節數int (*compar)(const void*, const void*));//這個其實就是一個 有比較功能函數 的指針
上面那個比較功能就是你要怎么實現這個排序,就用什么功能。例如:我要實現升序功能,那么這個函數就是實現升序的功能。?
我們現在就可以開始模擬實現冒泡排序了。
#include <stdio.h>
#include <stdlib.h>//qsort函數所需的頭文件//打印數據看看是否排序成功
void Print(int arr[], int sz)
{for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}
}//調用的排序函數
//由于創造這個函數的人,不知道我們會比較什么樣的數據,因此,就要void*來接收。
int int_cmp(const void* p1, const void* p2)
{//qsort默認的是升序,由于void*不能直接解引用,所以就先得強制轉換為要比較(int*)的數據類型return (*(int*)p1 - *(int*)p2);//如果我們像排成降序,就可以把這個給反過來
}int main()
{int arr[] = { 9,8,7,6,5,4,3,2,1,0 };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), int_cmp);Print(arr, sz);return 0;
}
可以看出來這個qsort函數排序是正確的。
使用qsort排序結構數據?
我們假設要排序一些不是整型的數據,那么冒泡排序肯定是不行的。但是我們可以采用其思想,來進行排序。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stu//創建一個結構體類型:學生
{char name[20];int age;
};int cmp_stu_by_name(const void* e1, const void* e2)
{return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
}void Print(struct stu* p, int sz)
{for (int i = 0; i < sz; i++){printf("%s ", (p+i)->name);//結構體指針->成員名}printf("\n");
}
int main()
{//創建一個結構體數組并且初始化struct stu arr[] = { {"zhangsan", 20},{"lisi" ,30}, {"wangwu", 18} };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);Print(arr, sz);return 0;
}
?strcmp是用來比較字符串大小的,具體用法請看:字符函數與字符串函數(上)-CSDN博客?
通過上面的學習,我們就可以發現這個qsort函數在使用時,需要我們根據自己的需求來寫出對應的比較函數。
結構體成員的間接訪問?
我們在訪問結構體成員時,有兩種操作符,一種是 . (直接訪問),還有一種是 ->(間接訪問)。
直接訪問在操作符詳解(下)-CSDN博客?里講過。
結構體指針->成員名 ,即當 -> 的左邊滿足時結構體指針時,我們要訪問結構體成員就可以用->。?
上面是排序其名字,我們還可以排序其年齡
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stu
{char name[20];int age;
};int cmp_stu_by_age(const void* e1, const void* e2)
{return (((struct stu*)e1)->age - ((struct stu*)e2)->age);
}void Print(struct stu* p, int sz)
{for (int i = 0; i < sz; i++){printf("%d ", (p + i)->age);}printf("\n");
}int main()
{struct stu arr[] = { {"zhangsan", 20},{"lisi" ,30}, {"wangwu", 18} };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);Print(arr, sz);return 0;
}
qsort函數的模擬實現?
我們現在就來通過模擬實現qsort函數(用冒泡的方式)來排序整形數組。
#include <stdio.h>
int cmp(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;
}//因為前面有強制轉換為char*了,所以我們也就不用void*了
void Swap(char* p1, char* p2, size_t width)
{//如果是排序char的數據,我們就只能一個字節一個字節的交換for (int i = 0; i < width; i++){char tmp = *(p1+i);*(p1+i) = *(p2+i);*(p2+i) = tmp;}
}void bubble_sort(void* base, size_t num, size_t width, int(*cmp)(void*, void*))
{for (int i = 0; i < num - 1; i++){for (int j = 0; j < num - 1 - i; j++){//如果前者大于后者,也就是降序,會返回一個大于0的數(根據這個cmp的函數來的)//不知道是啥類型,強制轉換為最小的就行(類型占字節最小的是字符型)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[] = { 9,8,7,6,5,4,3,2,1,0 };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), cmp);//采用冒泡的方式for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");return 0;
}