【C語言】回調函數,qsort排序函數的使用和自己實現,超詳解

文章目錄

  • 前言
  • 一、回調函數是什么
  • 二、回調函數的使用
    • 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函數可以幫助到大家,博主感覺他真的是很有用,以后會盡量使用到他的,希望本篇文章可以幫助到大家,謝謝大家閱讀!!!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/40806.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/40806.shtml
英文地址,請注明出處:http://en.pswp.cn/news/40806.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

金融術語總結

洗錢 將犯罪或其他非法違法行為所獲得的違法收入&#xff0c;通過各種手段掩飾、隱瞞、轉化&#xff0c;使其在形式上合法化的行為。 存量客戶 某個時間段里原先已有的客戶,與新增客戶相對應。 月活躍用戶數量&#xff0c;MAU&#xff08;Monthly Active User&#xff0c;M…

【go語言基礎】go中的方法

先思考一個問題&#xff0c;什么是方法&#xff0c;什么是函數&#xff1f; 方法是從屬于某個結構體或者非結構體的。在func這個關鍵字和方法名中間加了一個特殊的接收器類型&#xff0c;這個接收器可以是結構體類型的或者是非結構體類型的。從屬的結構體獲取該方法。 函數則…

【100天精通python】Day37:GUI界面編程_PyQT從入門到實戰(上)

目錄 專欄導讀 1 PyQt6 簡介&#xff1a; 1.1 安裝 PyQt6 和相關工具&#xff1a; 1.2 PyQt6 基礎知識&#xff1a; 1.2.1 Qt 的基本概念和組件&#xff1a; 1.2.2 創建和使用 Qt 窗口、標簽、按鈕等基本組件 1.2.3 布局管理器&#xff1a;垂直布局、水平布局、網格布局…

typedef函數代碼段解釋以及部分Windows下的系統函數

文章目錄 1、typedef int (WINAPI* LPSDOLInitialize)(const SDOLAppInfo* pAppInfo)2、typedef int (WINAPI* LPSDOLGetModule)(REFIID riid, void** intf)3、typedef int (WINAPI* LPSDOLTerminal)();4、GetProcAddress運行時獲取一個動態鏈接庫&#xff08;DLL&#xff09;中…

mysql與redis區別

mysql和redis的數據庫類型 mysql是關系型數據庫&#xff0c;主要用于存放持久化數據&#xff0c;將數據存儲在硬盤中&#xff0c;讀取速度較慢。 redis是NOSQL&#xff0c;即非關系型數據庫&#xff0c;也是緩存數據庫&#xff0c;即將數據存儲在緩存中&#xff0c;緩存的讀取速…

網絡

mcq Java 傳輸層&#xff1a;拆分和組裝&#xff0c;完成端到端的消息傳遞&#xff0c;流量控制&#xff0c;差錯控制等 網絡層&#xff1a; 尋址、路由&#xff0c;復用&#xff0c;擁塞控制&#xff0c;完成源到宿的傳遞。 顯然A選項是錯誤的&#xff0c;有流量控制的是傳輸層…

JavaScript TypeScript

文章目錄 JavaScript語法事件處理與HTML和CSS集成前端框架和庫 TypeScript靜態類型檢查語法更好的可維護性 包管理工具npmpnpmyarnBower JavaScript JavaScript&#xff08;簡稱JS&#xff09;是一種廣泛應用于網頁開發的腳本語言。它被用來為網頁增加交互性和動態功能。以下是…

netty學習分享(一)

TCP與UDP TCP 是面向連接的、可靠的流協議&#xff0c;通過三次握手建立連接&#xff0c;通訊完成時要拆除連接。 UDP是面向無連接的通訊協議&#xff0c;UDP通訊時不需要接收方確認&#xff0c;屬于不可靠的傳輸&#xff0c;可能會出現丟包現象 端口號&#xff1a; 端口號用…

【微信小程序】記一次自定義微信小程序組件的思路

最近來個需求&#xff0c;要求給小程序的 modal 增加個關閉按鈕&#xff0c;上網一查發現原來 2018 年就有人給出解決方案了&#xff0c;于是總結下微信小程序自定義組件的思路&#xff1a;一句話&#xff0c;用 wxml css實現和原生組件類似的樣式和效果&#xff0c;之后用 JS…

【uniapp】uniapp設置安全區域:

文章目錄 一、效果圖:二、實現代碼: 一、效果圖: 二、實現代碼: {"path": "pages/index/index","style": {"navigationStyle": "custom","navigationBarTextStyle": "white","navigationBarTitle…

消息隊列學習筆記

消息隊列基礎 適合消息隊列解決的問題 異步處理&#xff1a;處理完關鍵步驟后直接返回結果&#xff0c;后續放入隊列慢慢處理流量控制&#xff1a; 使用消息隊列隔離網關和后端服務&#xff0c;以達到流量控制和保護后端服務的目的。能根據下游的處理能力自動調節流量&#x…

leetcode做題筆記79單詞搜索

給定一個 m x n 二維字符網格 board 和一個字符串單詞 word 。如果 word 存在于網格中&#xff0c;返回 true &#xff1b;否則&#xff0c;返回 false 。 單詞必須按照字母順序&#xff0c;通過相鄰的單元格內的字母構成&#xff0c;其中“相鄰”單元格是那些水平相鄰或垂直相…

Matlab工具NIFTI包的基本功能函數

Matlab工具NIFTI包的基本功能函數 Nifti 格式最初是為神經影像學發明的。神經影像信息學技術計劃&#xff08;NIFTI&#xff09;將 NIfTI 格式預設為 ANALYZE7.5 格式的替代品。它最初的應用領域是神經影像&#xff0c;但是也被用在其他領域。這種格式的主要特點就是它包含兩個…

Docker基礎入門:常規軟件安裝與鏡像加載原理

Docker基礎入門&#xff1a;常規軟件安裝與鏡像加載原理 一、Docker常規軟件安裝1.1、部署nginx1.2、部署tomcat1.3、部署elasticsearch1.4、如何部署kibana-->連接elasticsearch1.5、部署可視化工具 二、 鏡像加載原理2.1、鏡像是什么2.2、Docker鏡像加速原理2.3、分層理解…

為什么我的集群一個 Spark Executor / Yarn Container 只分配一個vCore?

在很多集群里,在關閉了Spark的DynamicAllocation的前提下(避免自動申請空閑資源,干擾測試結果),都會觀察到:提交Spark作業時,申請 1 個 driver + n 個 executor 會在Yarn上對應創建 n+1 個 container,但是每個container只有一個vCore,通過--driver-cores和--executor-…

Grafana Prometheus 通過JMX監控kafka 【2023最新方式】

第三方kafka exporter方案 目前網上關于使用Prometheus 監控kafka的大部分資料都是使用一個第三方的 kafka exporter&#xff0c;他的原理大概就是啟動一個kafka客戶端&#xff0c;獲取kafka服務器的信息&#xff0c;然后提供一些metric接口供Prometheus使用&#xff0c;隨意它…

docker 安裝mysql8.0

1、拉取鏡像 docker pull mysql2、運行鏡像 docker run -d --restartalways --name mysql --privilegedtrue -p 3306:3306 -v /home/sunyuhua/docker/mysql/data:/var/lib/mysql -v /home/sunyuhua/docker/mysql/conf:/etc/mysql/conf.d -v /home/sunyuhua/docker/mysql/logs…

07_Hudi案例實戰、Flink CDC 實時數據采集、Presto、FineBI 報表可視化等

7.第七章 Hudi案例實戰 7.1 案例架構 7.2 業務數據 7.2.1 客戶信息表 7.2.2 客戶意向表 7.2.3 客戶線索表 7.2.4 線索申訴表 7.2.5 客戶訪問咨詢記錄表 7.3 Flink CDC 實時數據采集 7.3.1 開啟MySQL binlog 7.3.2 環境準備 7.3.3 實時采集數據 7.3.3.1 客戶信息表 7.3.3.2 客戶…

ubuntu安裝jdk、emqx、nginx

一、安裝jdk 要在Ubuntu上安裝JDK 1.8&#xff0c;您可以按照以下步驟進行操作&#xff1a; 打開終端&#xff08;CtrlAltT&#xff09;。確保您的系統已更新&#xff1a; sudo apt update sudo apt upgrade安裝OpenJDK 8&#xff1a; sudo apt install openjdk-8-jdk安裝完成…

.net core發布到IIS上出現 HTTP 錯誤 500.19

1.檢查.net core 環境運行環境是否安裝完成&#xff0c;類似如下環境 2.IIS是否安裝全 本次原因就是IIS未安裝全導致的 按照網上說的手動重啟iis&#xff08;iisreset&#xff09;也不行