指針的進階2

六、函數指針數組

字符指針數組 - 存放字符指針的數組 char* arr[10]

整型指針數組 - 存放整型指針的數組 int* arr[10]

函數指針數組 - 存放函數指針的數組

void my_strlen()
{}
int main()
{//指針數組char* ch[5];int arr[10] = {0};//pa是是數組指針int (*pa)[10] = &arr;//pf是函數指針int (*pf)(const void*) = &my_strlen;//函數指針數組int (*pf[10])(const void*) = {&my_strlen};//pf的類型是int (*[10])(const void*)return 0;
}

解釋pf 先和 [ ] 結合,說明 pf是數組,數組的內容是 int (*)() 類型的函數指針。

6.1轉移表

函數指針數組的用途:轉移表

舉例:寫一個計算器實現整數的加、減、乘、除

計算器的一般實現:

void menu()
{printf("********************\n");printf("***1. add  2. sub***\n");printf("***3. mul  4. div***\n");printf("***0. exit       ***\n");printf("********************\n");
}int Add(int x,int y)
{return x + y;
}int Sub(int x,int y)
{return x - y;
}int Mui(int x,int y)
{return x * y;
}int Div(int x,int y)
{return x / y;
}int main()
{int input = 0;int x = 0;int y =0;int ret = 0;do{menu();printf("請選擇:>");scanf("%d",&input);switch(input){case 1:printf("請輸入兩個操作數:>");scanf("%d %d",&x,&y);ret = Add(x,y);printf("%d\n",ret);break;case 2:printf("請輸入兩個操作數:>");scanf("%d %d",&x,&y);ret = Sub(x,y);printf("%d\n",ret);break;case 3:printf("請輸入兩個操作數:>");scanf("%d %d",&x,&y);ret = Mul(x,y);printf("%d\n",ret);break;case 4:printf("請輸入兩個操作數:>");scanf("%d %d",&x,&y);ret = Div(x,y);printf("%d\n",ret);break;case 0:printf("退出計算器\n");break;default:printf("選擇錯誤\n");break;}}while(input);return 0;
}

使用函數指針數組實現:

void menu()
{printf("********************\n");printf("***1. add  2. sub***\n");printf("***3. mul  4. div***\n");printf("***0. exit       ***\n");printf("********************\n");
}int Add(int x,int y)
{return x + y;
}int Sub(int x,int y)
{return x - y;
}int Mui(int x,int y)
{return x * y;
}int Div(int x,int y)
{return x / y;
}//用函數指針數組存放上述函數的地址
//轉移表
int (*pf[5])(int,int) = {NULL,Add,Sub,Mul,Div};//第一個元素是NULL(0),是為了使得函數與菜單中的選項數字一致int main()
{int input = 0;int x = 0;int y =0;int ret = 0;do{menu();printf("請選擇:>");scanf("%d",&input);if(input == 0){printf("退出計算器\n");break;}else if(input >= 1 && innput <=4){printf("請輸入兩個操作數:>");scanf("%d %d",&x,&y);ret = pf[input](x,y);printf("%d\n",ret);}else{printf("選擇錯誤\n");}}while(input);    return 0;
}

七、指向函數指針數組的指針

指向函數指針數組的指針是一個指針,指針指向一個數組,數組的元素都是函數指針

int main()
{//數組指針int arr[10];int (*pa)[10] = &arr;//函數指針int (*pf)(int,int) = &test;//函數指針數組int (*pf[5])(int ,int) = {test};pf[0] = test;//ppf是指向函數指針數組的指針int (*(*ppf)[5])(int,int) = &pf//ppf的類型是int (*(*)[5])(int,int)return 0;
}

八、回調函數

回調函數就是?個通過函數指針調用的函數。
如果你把函數的指針(地址)作為參數傳遞給另?個函數,當這個指針被用來調用其所指向的函數
時,被調用的函數就是回調函數。回調函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用于對該事件或條件進行響應。

可以使用回調函數來實現計算器,使其更加簡化:

void menu()
{printf("********************\n");printf("***1. add  2. sub***\n");printf("***3. mul  4. div***\n");printf("***0. exit       ***\n");printf("********************\n");
}int Add(int x,int y)
{return x + y;
}int Sub(int x,int y)
{return x - y;
}int Mui(int x,int y)
{return x * y;
}int Div(int x,int y)
{return x / y;
}//以上都稱為回調函數void calc(int (*pf)(int ,int))
{int x = 0;int y =0;int ret = 0;printf("請輸入兩個操作數:>");scanf("%d %d",&x,&y);ret = pf(x,y);printf("%d\n",ret);
}int main()
{int input = 0;do{menu();printf("請選擇:>");scanf("%d",&input);switch(input){case 1:calc(Add);break;case 2:calc(Sub);break;case 3:calc(Mul);break;case 4:calc(Div);break;case 0:printf("退出計算器\n");break;default:printf("選擇錯誤\n");break;}}while(input);return 0;
}
把調用的函數的地址以參數的形式傳遞過去,使?函數指針接收,函數指針指向什么函數就調?什么函數,這?其實使?的就是回調函數的功能

8.1qsort函數的使用

首先回顧一下冒泡排序:思想:兩兩相鄰的元素進行比較

例如進行升序排序:

void bubble_sort(int arr[],int sz)
{//趟數int i = 0;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;}}}
}
int main()
{//對數組進行排序,升序int arr[10] = {9,8,7,6,5,4,3,2,1,0};int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr,sz);//0 1 2 3 4 5 6 7 8 9//打印int i = 0;for(i = 0;i <sz; i++){printf("%d ",arr[i]);}return 0;
}

冒泡排序是有缺點的:只能排序整數,結構體、浮點型等不可以

qsort函數的使用

庫函數中有一個排序函數:qsort(快速排序)

void* base - 待排序的數組的起始位置(地址)?
size_t num - 數組元素個數
size_t size - 數組中每一個元素的大小(一個元素是幾個字節)
int (*compar)(const void*, const void*) - 兩個元素的比較函數(函數指針),第一個參數是進行比較的兩個元素中第一個的地址,第二個參數是另一個元素地址
比較函數的參數是void*類型的原因:因為無法確定想要比較的類型是int、結構體等類型中的哪一種,所以設置成void(無具體類型)類型

int main()
{int a = 10;float f = 5.5f;int* p = &a;//p = &f;//如果把f的地址取出來賦給p,浮點型的地址賦給整型的指針,編譯器會報警告:類型不兼容//如果寫成void*的指針類型void* pp = &f;//void*的指針可以接收float類型的地址,且不會報警告pp = &a;//用void*的指針接收整型地址也不會警告//pp - 垃圾桶(可以接受任何類型的地址,因為pp是void*類型的指針變量,無具體類型)printf("%f\n", *pp);//不能直接打印,會報錯,void*的指針不能直接解引用pp++;//進行++也不行,因為不知道具體類型,不知道具體加一步要走多遠(大小不知道)return 0;
}

但是也有缺點:沒有辦法直接使用,因為void*的指針不能直接解引用,不知道具體類型,如果想要使用,要進行強制類型轉換,就可以使用了

---------------------------------------------------------------------------------------------------------------------------------

進一步解析比較函數:當比較函數接收的兩個元素進行比較時,p1>p2 - 返回大于0的數字

p1<p2 - 返回小于0的數字;p1=p2 - 等于0

前面我們說過要對數組進行升序排序,那么我們就可以根據以上的信息,轉化為兩個元素相減的結果,再根據此結果來判斷是否需要進行交換 ,如果相減的結果大于0,說明p1>p2,要進行交換

qsort函數的使用需要包含頭文件 #include <stdlib.h>

8.1.1使用qsort函數排序整型數據

#include <stdio.h>
#include <stdlib.h>int cmp_int(const void* p1,const void* p2)
{return *(int*)p1 - *(int*)p2;//升序return *(int*)p2 - *(int*)p1;//降序
}
int main()
{//對數組進行排序,升序int arr[10] = {9,8,7,6,5,4,3,2,1,0};int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr,sz,sizeof(arr[0]),cmp_int);int i = 0;for(i = 0;i <sz; i++){printf("%d ",arr[i]);}return 0;
}

8.1.2使用qsort函數排序結構體數據

按照年齡排序:

#include <stdio.h>
#include <stdlib.h>struct Stu
{char name[20];int age;
};//按照學生的年齡來排序
int cmp_stu_by_age(const void* p1,const void* p2)
{return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}int main()
{struct Stu s[3] = {{"zhangsan",20},{"lisi",50},{"wangwu",33}};int sz = sizeof(s) / sizeof(s[0]);qsort(s,sz,sizeof(s[0]),cmp_stu_by_age);int i = 0;for(i = 0;i < sz; i++){printf("姓名:%s 年齡:%d\n",s[i].name,s[i].age);}return 0;
}

按照姓名排序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>struct Stu
{char name[20];int age;
};//按照學生的姓名來排序
int cmp_stu_by_name(const void* p1,const void* p2)
{return strcmp(((struct Stu*)p1)->name,((struct Stu*)p2)->name);
}int main()
{struct Stu s[3] = {{"zhangsan",20},{"lisi",50},{"wangwu",33}};int sz = sizeof(s) / sizeof(s[0]);qsort(s,sz,sizeof(s[0]),cmp_stu_by_name);int i = 0;for(i = 0;i < sz; i++){printf("姓名:%s 年齡:%d\n",s[i].name,s[i].age);}return 0;
}

字符串是按照字典序排序的:
字典序是一種基于字母或字符順序的排列方式,類似于字典中單詞的排列規則。在C語言中,常用于字符串或字符數組的比較和排序。

字典序的核心規則?
?逐字符比較?從左到右逐個比較字符的ASCII。若字符不同,ASCII值較小的字符所在的字符串更小。若字符相同,繼續比較下一個字符。
?長度優先?:若所有字符相同,則較短的字符串更小。
?示例?:"apple" < "banana"(因為 'a' < 'b')
"app" < "apple"(前三個字符相同,但前者更短)
?C語言中的字典序實現?:
使用標準庫函數 strcmp
strcmp 是C語言標準庫(<string.h>)中用于比較字符串的函數,按字典序返回結果:

?返回值?:
< 0:第一個字符串小于第二個。
= 0:兩個字符串相等。
> 0:第一個字符串大于第二個。

注意事項:字符編碼默認基于ASCII值,大寫字母(A-Z,ASCII 65~90)比小寫字母(a-z,ASCII 97~122)小

字符串以終止符\0結尾,比較時會自動處理

8.2qsort函數的模擬實現

根據qsort函數,改造冒泡排序,使得這個函數可以排序任意指定的數組(以冒泡排序的思維實現qsort函數)

8.2.1排序整型數組

//使用我們自己寫的bubble_sort函數排序整型數組void Swap(char* a,char* b,int size)
{int i = 0;for(i = 0;i < size; i++){char tmp = *a;*a = *b;*b = tmp;a++;b++;}
}
int cmp_int(const void* p1,const void* p2)
{return *(int*)p1 - *(int*)p2;
}
void bubble_sort(void* base,size_t num,size_t size,int (*cmp)(const void* p1,const void* p2))
{//趟數size_t i = 0;for(i = 0;i < num-1; i++){size_t j = 0;for(j = 0;j < num-1-i; j++){if(cmp((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};int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr,sz,sizeof(arr[0]),cmp_int);int i = 0;for(i = 0;i < sz; i++){printf("%d ",arr[i]);}return 0;
}

8.2.2排序結構體數組

按照年齡排序:

struct Stu
{char name[20];int age;
};
void Swap(char* a,char* b,int size)
{int i = 0;for (i = 0; i < size; i++){char tmp = *a;*a = *b;*b = tmp;a++;b++;}
}
//按照年齡排序
int cmp_stu_by_age(const void* p1,const void* p2)
{return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}
void bubble_sort(void* base,size_t num,size_t size,int (*cmp)(const void* p1,const void* p2))
{//趟數int i = 0;for(i = 0;i < num -1; i++){int j = 0;for(j = 0;j < num-1-i; j++){if(cmp((char*)base+j*size,(char*)base+(j+1)*size) > 0){Swap(cmp((char*)base+j*size,(char*)base+(j+1)*size,size);}}}
}
int main()
{struct Stu s[3] = {{"zhangsan",20},{"lisi",50},{"wangwu",33}};int sz = sizeof(s) / sizeof(s[0]);bubble_sort(s,sz,sizeof(s[0]),cmp_stu_by_age);int i = 0;for(i = 0;i < sz; i++){printf("姓名:%s 年齡:%d\n",s[i].name,s[i].age);}return 0;
}

按照姓名排序:

struct Stu
{char name[20];int age;
};
void Swap(char* a,char* b,int size)
{int i = 0;for (i = 0; i < size; i++){char tmp = *a;*a = *b;*b = tmp;a++;b++;}
}
//按照姓名排序
int cmp_stu_by_name(const void* p1,const void* p2)
{return strcmp(((struct Stu*)p1)->name,((struct Stu*)p2)->name);
}
void bubble_sort(void* base,size_t num,size_t size,int (*cmp)(const void* p1,const void* p2))
{//趟數int i = 0;for(i = 0;i < num -1; i++){int j = 0;for(j = 0;j < num-1-i; j++){if(cmp((char*)base+j*size,(char*)base+(j+1)*size) > 0){Swap(cmp((char*)base+j*size,(char*)base+(j+1)*size,size);}}}
}
int main()
{struct Stu s[3] = {{"zhangsan",20},{"lisi",50},{"wangwu",33}};int sz = sizeof(s) / sizeof(s[0]);bubble_sort(s,sz,sizeof(s[0]),cmp_stu_by_name);int i = 0;for(i = 0;i < sz; i++){printf("姓名:%s 年齡:%d\n",s[i].name,s[i].age);}return 0;
}

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

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

相關文章

速盾:高防CDN節點對收錄有影響嗎?

引言 搜索引擎收錄是網站運營中至關重要的環節&#xff0c;它直接影響著網站的曝光度和流量。近年來&#xff0c;隨著網絡安全威脅的增加&#xff0c;許多企業開始采用高防CDN&#xff08;內容分發網絡&#xff09;來保護其網站免受DDoS攻擊和其他形式的網絡攻擊。然而&#x…

2025藍橋杯省賽C/C++研究生組游記

前言 至少半年沒寫算法題了&#xff0c;手生了不少&#xff0c;由于python寫太多導致行末老是忘記打分號&#xff0c;printf老是忘記寫f&#xff0c;for和if的括號也老是忘寫&#xff0c;差點連&&和||都忘記了。 題目都是回憶版本&#xff0c;可能有不準確的地方。 …

Quill富文本編輯器支持自定義字體(包括新舊兩個版本,支持Windings 2字體)

文章目錄 1 新版&#xff08;Quill2 以上版本&#xff09;2 舊版&#xff08;Quill1版本&#xff09; 1 新版&#xff08;Quill2 以上版本&#xff09; 注意&#xff1a;新版設置 style"font-family: Wingdings 2" 這種帶空格的字體樣式會被過濾掉&#xff0c;故需特…

dbt:新一代數據轉換工具

dbt&#xff08;Data Build Tool&#xff09;一款專為數據分析和工程師設計的開源工具&#xff0c;專注于 ETL/ELT 流程的數據轉換&#xff08;Transform&#xff09;環節&#xff0c;幫助用戶以高效、可維護的方式將原始數據轉換為適合分析的數據模型。 用戶只需要編寫查詢&am…

【家政平臺開發(39)】解鎖家政平臺測試秘籍:計劃與策略全解析

本【家政平臺開發】專欄聚焦家政平臺從 0 到 1 的全流程打造。從前期需求分析,剖析家政行業現狀、挖掘用戶需求與梳理功能要點,到系統設計階段的架構選型、數據庫構建,再到開發階段各模塊逐一實現。涵蓋移動與 PC 端設計、接口開發及性能優化,測試階段多維度保障平臺質量,…

Java中的Map vs Python字典:核心對比與使用指南

一、核心概念 1. 基本定義 Python字典&#xff08;dict&#xff09; &#xff1a;動態類型鍵值對集合&#xff0c;語法簡潔&#xff0c;支持快速查找。Java Map&#xff1a;接口&#xff0c;常用實現類如 HashMap、LinkedHashMap&#xff0c;需聲明鍵值類型&#xff08;泛型&…

C語言基礎之數組

1. 一維數組的創建和初始化 數組的創建 數組是一組相同類型元素的集合。 數組的創建方式&#xff1a; type_t arr_name [const_n]; //type_t 是指數組的元素類型 //const_n是一個常量表達式&#xff0c;用來指定數組的大小 數組創建的實例&#xff1a; //代碼1int arr1[10]; …

虛幻引擎5-Unreal Engine筆記之“將MyStudent變量設置為一個BP_Student的實例”這句話如何理解?

虛幻引擎5-Unreal Engine筆記之“將MyStudent變量設置為一個BP_Student的實例”這句話如何理解&#xff1f; code review! 文章目錄 虛幻引擎5-Unreal Engine筆記之“將MyStudent變量設置為一個BP_Student的實例”這句話如何理解&#xff1f;理解這句話的關鍵點1.類&#xff08…

提示詞 (Prompt)

引言 在生成式 AI 應用中&#xff0c;Prompt&#xff08;提示&#xff09;是與大型語言模型&#xff08;LLM&#xff09;交互的核心輸入格式。Prompt 的設計不僅決定了模型理解任務的準確度&#xff0c;還直接影響生成結果的風格、長度、結構與可控性。隨著模型能力和應用場景…

十二、C++速通秘籍—靜態庫,動態庫

上一章節&#xff1a; 十一、C速通秘籍—多線程-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/147055932?spm1001.2014.3001.5502 本章節代碼&#xff1a; cpp2/library CuiQingCheng/cppstudy - 碼云 - 開源中國https://gitee.com/cuiqingcheng/cppst…

什么是繼承?js中有哪兒些繼承?

1、什么是繼承&#xff1f; 繼承是面向對象軟件技術中的一個概念。 2、js中有哪兒些繼承&#xff1f; js中的繼承有ES6的類class的繼承、原型鏈繼承、構造函數繼承、組合繼承、寄生組合繼承。 2.1 ES6中類的繼承 class Parent {constructor() {this.age 18;} }class Chil…

Linux進程通信入門:匿名管道的原理、實現與應用場景

Linux系列 文章目錄 Linux系列前言一、進程通信的目的二、進程通信的原理2.1 進程通信是什么2.2 匿名管道通訊的原理 三、進程通訊的使用總結 前言 Linux進程間同通訊&#xff08;IPC&#xff09;是多個進程之間交換數據和協調行為的重要機制&#xff0c;是我們學習Linux操作系…

探秘Transformer系列之(26)--- KV Cache優化 之 PD分離or合并

探秘Transformer系列之&#xff08;26&#xff09;— KV Cache優化 之 PD分離or合并 文章目錄 探秘Transformer系列之&#xff08;26&#xff09;--- KV Cache優化 之 PD分離or合并0x00 概述0x01 背景知識1.1 自回歸&迭代1.2 KV Cache 0x02 靜態批處理2.1 調度策略2.2 問題…

十大PDF解析工具在不同文檔類別中的比較研究

PDF解析對于包括文檔分類、信息提取和檢索在內的多種自然語言處理任務至關重要&#xff0c;尤其是RAG的背景下。盡管存在各種PDF解析工具&#xff0c;但它們在不同文檔類型中的有效性仍缺乏充分研究&#xff0c;尤其是超出學術文檔范疇。通過使用DocLayNet數據集&#xff0c;比…

HarmonyOS-ArkUI 裝飾器V2 @ObservedV2與@Trace裝飾器

參考文檔: 文檔中心https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V14/arkts-new-observedv2-and-trace-V14#trace%E8%A3%85%E9%A5%B0%E5%AF%B9%E8%B1%A1%E6%95%B0%E7%BB%84由于V2的裝飾器比V1的裝飾器更加易用,盡管學習的過程中用到的都是V1的裝飾器,但…

GPT - GPT(Generative Pre-trained Transformer)模型框架

本節代碼主要為實現了一個簡化版的 GPT&#xff08;Generative Pre-trained Transformer&#xff09;模型。GPT 是一種基于 Transformer 架構的語言生成模型&#xff0c;主要用于生成自然語言文本。 1. 模型結構 初始化部分 class GPT(nn.Module):def __init__(self, vocab…

基于FPGA的六層電梯智能控制系統 矩陣鍵盤-數碼管 上板仿真均驗證通過

基于FPGA的六層電梯智能控制系統 前言一、整體方案二、軟件設計總結 前言 本設計基于FPGA實現了一個完整的六層電梯智能控制系統&#xff0c;旨在解決傳統電梯控制系統在別墅環境中存在的個性化控制不足、響應速度慢等問題。系統采用Verilog HDL語言編程&#xff0c;基于Cyclo…

車載通信系統中基于ISO26262的功能安全與抗輻照協同設計研究

摘要&#xff1a;隨著智能網聯汽車的快速發展&#xff0c;車載通信系統正面臨著功能安全與抗輻照設計的雙重挑戰。在高可靠性要求的車載應用場景下&#xff0c;如何實現功能安全標準與抗輻照技術的協同優化&#xff0c;構建滿足ISO26262安全完整性等級要求的可靠通信架構&#…

Node.js種cluster模塊詳解

Node.js 中 cluster 模塊全部 API 詳解 1. 模塊屬性 const cluster require(cluster);// 1. isMaster // 判斷當前進程是否為主進程 console.log(是否為主進程:, cluster.isMaster);// 2. isWorker // 判斷當前進程是否為工作進程 console.log(是否為工作進程:, cluster.isW…

融合動態權重與抗刷機制的網文評分系統——基于優書網、IMDB與Reddit的混合算法實踐

? Yumuing 博客 &#x1f680; 探索技術的每一個角落&#xff0c;解碼世界的每一種可能&#xff01; &#x1f48c; 如果你對 AI 充滿好奇&#xff0c;歡迎關注博主&#xff0c;訂閱專欄&#xff0c;讓我們一起開啟這段奇妙的旅程&#xff01; 以權威用戶為核心&#xff0c;時…