C語言指針詳解(三)

?

目錄

前言?

一. 回調函數是什么?

?1.定義

2.?代碼示例:計數器

2.1 使用回調函數改造前

? 2.2 使用回調函數改造后

二. qsort使用舉例

1.? qsort介紹

2.?使用qsort函數排序整型數據

3.?使用qsort排序結構體數據

三. qsort函數的模擬實現

四. sizeof和strlen的對比

1.?sizeof

2.?strlen

3.?sizeof 和 strlen的對比

寫在最后


前言?

C語言指針詳解(一)icon-default.png?t=N7T8https://blog.csdn.net/qq_51904510/article/details/136810287

C語言指針詳解(二)icon-default.png?t=N7T8https://blog.csdn.net/qq_51904510/article/details/138172497

前面我們了解了指針的指針的指針的絕大多數知識,現在,我們來了解回調函數的定義、使用以及意義,了解可以快速排序元素的函數——qsort的使用方法和模擬實現,以及sizeof和strlen的對比

一. 回調函數是什么?

?1.定義

回調函數就是一個通過函數指針調用的函數

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

之前我們寫的計數器的實現的代碼中,有一部分的代碼是重復出現的,其中雖然執行計算的邏輯是區別的,但是輸入輸出操作是冗余的,有沒有辦法,簡化一些呢?

因為紅色框中的代碼,只有調用函數的邏輯是有差異的,我們可以把調用的函數的地址以參數的形式傳遞過去,使用函數指針接收,函數指針指向什么函數就調用什么函數,這里其實使用的就是回調函數的功能。

2.?代碼示例:計數器

2.1 使用回調函數改造前

#include <stdio.h>
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 x, y;int input = 1;int ret = 0;do{printf("*********************\n");printf("*  1: add   2: sub  *\n");printf("*  3: mul   4: div  *\n");printf("*********************\n");printf("請選擇:");scanf("%d", &input);switch (input){case 1:printf("輸入操作數:");scanf("%d %d", &x, &y);ret = add(x, y);printf("ret = %d\n", ret);break;case 2:printf("輸入操作數:");scanf("%d %d", &x, &y);ret = sub(x, y);printf("ret = %d\n", ret);break;case 3:printf("輸入操作數:");scanf("%d %d", &x, &y);ret = mul(x, y);printf("ret = %d\n", ret);break;case 4:printf("輸入操作數:");scanf("%d %d", &x, &y);ret = div(x, y);printf("ret = %d\n", ret);break;case 0:printf("退出程序\n");break;default:printf("選擇錯誤\n");break;}} while (input);return 0;
}

? 2.2 使用回調函數改造后

#include <stdio.h>
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;
}void calc(int(*pf)(int, int))
{int ret = 0;int x, y;printf("輸入操作數:");scanf("%d %d", &x, &y);ret = pf(x, y);printf("ret = %d\n", ret);
}int main()
{int x, y;int input = 1;int ret = 0;do{printf("*********************\n");printf("*  1: add   2: sub  *\n");printf("*  3: mul   4: div  *\n");printf("*********************\n");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;
}

?我們可以發現,在使用回調函數后,有效的減少了代碼量,通過傳遞函數指針的形式,完成了計數器不同計算功能的實現,同時減少了大量的重復代碼部分

二. qsort使用舉例

1.? qsort介紹

qsort可以對數組的元素進行排序

對數組的元素進行排序,每個元素的字節長度為 size,使用自己編寫的compar函數確定順序。
此函數使用的排序算法通過調用指定的函數來比較元素對,并將指向它們的指針作為參數。
該函數不返回任何值,而是通過重新排序其元素來修改指向的數組的內容

使用時需要包含庫函數<stdlib.h>

函數原型為:

void qsort (void* base, size_t num, size_t size,int (*compar)(const void*,const void*));

?參數介紹:

參數介紹

返回值:

該函數無返回值

相當于:

void qsort (數組指針, 數組元素個數, 每個元素大小,自己編寫的比較大小的函數指針);

注意:qsort與bubble_sort時間復雜度相同,均為O(n^2)?

2.?使用qsort函數排序整型數據

#include <stdio.h>
#include <stdlib.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);for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%d ", arr[i]);}printf("\n");return 0;
}

運行結果

3.?使用qsort排序結構體數據

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Stu //學?
{char name[20];//名字int age;//年齡
};
//打印結構體
void printstruct(struct Stu* s, size_t sz)
{for (int i = 0; i < sz; i++){printf("%s %d  ", s[i].name, s[i].age);if (i == sz - 1){printf("\n");}}
}
//假設按照年齡來比較
int cmp_stu_by_age(const void* e1, const void* e2)
{return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
//strcmp - 是庫函數,是專門用來比較兩個字符串的大小的
//假設按照名字來比較
int cmp_stu_by_name(const void* e1, const void* e2)
{return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
//按照年齡來排序
void test2()
{struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);printstruct(&s, sz);
}
//按照名字來排序
void test3()
{struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);printstruct(&s, sz);
}
int main()
{test2();test3();return 0;
}

運行結果

三. qsort函數的模擬實現

使用回調函數,模擬實現qsort(采用冒泡的方式)。

注意:這里第一次使用 void* 的指針。

#include <stdio.h>
int int_cmp(const void* p1, const void* p2)
{return (*(int*)p1 - *(int*)p2);
}
void _swap(void* p1, void* p2, int size)
{int i = 0;for (i = 0; i < size; i++){char tmp = *((char*)p1 + i);*((char*)p1 + i) = *((char*)p2 + i);*((char*)p2 + i) = tmp;}
}
void bubble(void* base, int count, int size, int(*cmp)(void*, void*))
{int i = 0;int j = 0;for (i = 0; i < count - 1; i++){for (j = 0; j < count - i - 1; 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[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };int i = 0;bubble(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;
}

運行結果

四. sizeof和strlen的對比

1.?sizeof

在學習操作符的時候,我們學習了 sizeof , sizeof 計算變量所占內存內存空間大小的,單位是字節,如果操作數是類型的話,計算的是使用類型創建的變量所占內存空間的大小。

sizeof 只關注占用內存空間的大小,不在乎內存中存放什么數據。

比如:

#include <stdio.h>
int main()
{int a = 10;printf("sizeof(a)   = %d\n", sizeof(a));printf("sizeof a    = %d\n", sizeof a);printf("sizeof(int) = %d\n", sizeof(int));return 0;
}

運行結果

2.?strlen

strlen 是C語言庫函數,功能是求字符串長度。函數原型如下:

size_t strlen ( const char * str );

統計的是從 strlen 函數的參數 str 中這個地址開始向后, \0 之前字符串中字符的個數。

strlen 函數會一直向后找 \0 字符,直到找到為止,所以可能存在越界查找

#include <stdio.h>
#include <string.h>
int main()
{char arr1[3] = { 'a', 'b', 'c' };char arr2[] = "abc";printf("strlen(arr1) = %d\n", strlen(arr1));printf("strlen(arr2) = %d\n", strlen(arr2));printf("sizeof(arr1) = %d\n", sizeof(arr1));printf("sizeof(arr2) = %d\n", sizeof(arr2));return 0;
}

運行結果

3.?sizeof 和 strlen的對比

sizeof 和 strlen的對比
sizeofstrlen
sizeof是操作符strlen是庫函數,使用需要包含頭文件 string.h
sizeof計算操作數所占內存的大小,單位是字節srtlen是求字符串長度的,統計的是 \0 之前字符的隔個數
sizeof不關注內存中存放什么數據關注內存中是否有 \0 ,如果沒有 \0 ,就會持續往后找,可能會越界

寫在最后

到這里我們就了解了指針的絕大多數知識,仔細想想,也不像網上說得那樣難以理解吧,我們可能會認為C語言對指針的管理太松,很多問題都需要程序員自己去發現,去解決。然而,正是因為C語言對程序員十分放心,沒有引入太多的檢查,所以C語言的運行速度相當快,許多操作系統的內核如Windows也是用C語言編寫,C語言的許多庫函數運行效率也是相當高的。C語言從誕生到現在,經歷了時間的考驗,說明其本身是一個十分優秀的語言,值得我們去用心學習。

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

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

相關文章

代碼隨想錄:螺旋矩陣II相關題目推薦(54、LCR146)

59.螺旋矩陣II 題目 給你一個正整數 n &#xff0c;生成一個包含 1 到 n2 所有元素&#xff0c;且元素按順時針順序螺旋排列的 n x n 正方形矩陣 matrix 。 示例 1&#xff1a; 輸入&#xff1a;n 3 輸出&#xff1a;[[1,2,3],[8,9,4],[7,6,5]] 代碼&#xff08;新解法&am…

MyBatis——MyBatis 參數處理

一、單個簡單類型參數 簡單類型包括&#xff1a; byte short int long float double char Byte Short Integer Long Float Double Character String java.util.Date java.sql.Date parameterType 屬性&#xff1a;告訴 MyBatis 參數的類型 MyBatis 自帶類型自動推斷機制…

LLM應用-prompt提示:生成搜索相關問題、生成回答格式包含參考資料

參考: https://isou.chat/ (AI回答與相關問題都是根據問題的搜索引擎結果結合大模型生成的) prompt參考: https://github.com/yokingma/search_with_ai/blob/6d32aa8f05f5f6ee12b5204787035b3f7797c22a/src/prompt.ts#L8 ##rag 根據搜索結果知識回答RagQueryPrompt = ` …

在Go語言中,可以這樣使用Json

在Go語言中&#xff0c;處理JSON數據通常涉及編碼&#xff08;將Go結構體轉換為JSON字符串&#xff09;和解碼&#xff08;將JSON字符串轉換為Go結構體&#xff09;。Go標準庫中的encoding/json包提供了這些功能。第三方插件可以使用"github.com/goccy/go-json"也有同…

Git | git log 和 git status 的區別

如是我聞&#xff1a; git log和git status是Git中的兩個非常有用的命令&#xff0c;它們用于不同的目的&#xff0c;并提供不同類型的信息。 git log git log命令用于顯示一個或多個分支的提交歷史記錄。這個命令會列出提交歷史&#xff0c;包括每次提交的SHA-1哈希值、提交…

程控水冷阻性負載主要工作方式

程控水冷阻性負載是一種先進的電力設備&#xff0c;主要用于電力系統的測試和研究。它的主要工作方式是通過控制水冷系統的溫度&#xff0c;來模擬不同的阻性負載條件&#xff0c;從而對電力設備進行各種性能測試。 首先&#xff0c;我們需要了解什么是阻性負載。阻性負載是指那…

博弈智能的特點

博弈智能是指通過算法和模型對博弈過程進行分析和決策的智能系統。在博弈中&#xff0c;各方參與者追求自身利益和目標&#xff0c;會采取各種策略來達到自己的目標。其中&#xff0c;包括了一些不正當手段&#xff0c;如詭計和欺騙&#xff08;詭&#xff09;&#xff08;詐&a…

代碼隨想錄算法訓練營Day 42| 動態規劃part04 | 01背包問題理論基礎I、01背包問題理論基礎II、416. 分割等和子集

代碼隨想錄算法訓練營Day 42| 動態規劃part04 | 01背包問題理論基礎I、01背包問題理論基礎II、416. 分割等和子集 文章目錄 代碼隨想錄算法訓練營Day 42| 動態規劃part04 | 01背包問題理論基礎I、01背包問題理論基礎II、416. 分割等和子集01背包問題理論基礎一、01背包問題二、…

WSL設置啟動時自動啟動docker服務或其他服務

方式一: Windows系統的WSL,當windows關機再開機后,WSL等于是重新開機的,默認情況下,不會啟動Docker服務。例如在Ubuntu 22.04中,需要使用命令 service docker start來啟動。由于我習慣關機斷電,因此每天開機打開WSL后都要手動輸入這個命令,非常麻煩。所以找了一個方法…

Redis教程——哨兵

在上篇文章我們學習了Redis教程——主從復制&#xff0c;這篇文章我們學習Redis教程——哨兵監控。 在主從復制中如果主機發生宕機&#xff0c;從機Redis會一直等到主機的恢復&#xff0c;這樣會導致只能進行讀操作&#xff0c;不能進行寫操作&#xff0c;這大大降低了系統的高…

資料同化 | 搭建docker環境-1

Community Gridpoint Statistical Interpolation (GSI) system DTC 是一個分布式設施&#xff0c;NWP 社區可以在這里測試和評估用于研究和操作的新模型和技術。 DTC的目標包括&#xff1a; 鏈接研究和操作社區 研究成果轉化為實際操作的速度 加快改善天氣預報 開發和測試有…

Cocos Creator 3.8.x 透明帶滾動功能的容器

ScrollView 是一種帶滾動功能的容器 1、刪除ScrollView下Sprite組件的SpriteFrame 2、ScrollView下scrollBar的Sprite組件的Color設為&#xff1a;FFFFFF00 3、ScrollView下view的Graphics組件的FillColor設為&#xff1a;FFFFFF00

IP代理如何幫助SEO進行優化?

IP代理在SEO優化中扮演著重要的角色&#xff0c;它通過多種方式幫助提升網站的搜索排名和可見性。以下是IP代理如何幫助SEO進行優化的詳細闡述&#xff1a; 第一點&#xff0c;數據采集與分析&#xff1a;在SEO過程中&#xff0c;大量的數據是必不可少的。通過使用IP代理&…

如何區分os.walk()與os.scandir()

os.walk() import os for dirpath, dirname, files in os.walk(./):# dirpath 當前——路徑# dirname 當前——路徑——下——文件夾名——列表# files 當前——路徑——下——文件——列表dirpath 當前路徑 ./ dirname 當前路徑下面文件夾名稱組成的列表&#xff0c;共3個文…

c++ std::shared_ptr學習

背景 c中智能指針shared_ptr用于自動管理資源&#xff0c;通過引用計數來記錄資源被多少出地方使用。在不使用資源時&#xff0c;減少引用計數&#xff0c;如果引用計數為0&#xff0c;表示資源不會再被使用&#xff0c;此時會釋放資源。本文記錄對c中std::shared_ptr的源碼學習…

攻防世界PHP2

1、打開靶機鏈接http://61.147.171.105:49513/&#xff0c;沒有發現任何線索 2、嘗試訪問http://61.147.171.105:49513/index.php&#xff0c;頁面沒有發生跳轉 3、嘗試將訪問 嘗試訪問http://61.147.171.105:49513/index.phps index.php 和 index.phps 文件之間的主要區別在于…

GNU Radio創建時間戳 C++ OOT塊

文章目錄 前言一、創建自定義的 C OOT 塊1、創建 timestamp_sender C OOT 模塊①、創建 timestamp_sender OOT 塊②、修改 C 代碼 2、創建 timestamp_receiver C OOT 模塊①、創建 timestamp_receiver OOT 塊②、修改 C 代碼 3、創建 delayMicroSec C OOT 模塊①、創建 delayMi…

Vue3實戰筆記(20)—封裝頭部導航組件

文章目錄 前言一、封裝頭部導航欄二、使用步驟總結 前言 Vue 3 封裝頭部導航欄有助于提高代碼復用性、統一風格、降低維護成本、提高可配置性和模塊化程度&#xff0c;同時還可以實現動態渲染等功能&#xff0c;有利于項目開發和維護。 一、封裝頭部導航欄 封裝頭部導航欄&am…

HFSS學習-day4-建模操作

通過昨天的學習&#xff0c;我們已經熟悉了HFSS的工作環境&#xff1b;今天我們來講解HFSS中創建物體模型的縣體步驟和相關操作。物體建模是HFSS仿真設計工作的第一步&#xff0c;HFSS中提供了諸如矩形、圓面、長方體圓柱體和球體等多種基本模型(Primitive)&#xff0c;這些基本…

新書速覽|MATLAB科技繪圖與數據分析

提升你的數據洞察力&#xff0c;用于精確繪圖和分析的高級MATLAB技術。 本書內容 《MATLAB科技繪圖與數據分析》結合作者多年的數據分析與科研繪圖經驗&#xff0c;詳細講解MATLAB在科技圖表制作與數據分析中的使用方法與技巧。全書分為3部分&#xff0c;共12章&#xff0c;第1…