【C語言進階】帶你由淺入深了解指針【第四期】:數組指針的應用、介紹函數指針

前言

上一期講了數組指針的原理,這一期接著上一期講述數組指針的應用以及數組參數、函數參數。

? ? ? ? ?首先看下面的代碼進行上一期內容的復習,pc應該是什么類型?

char* arr[5] = {0};
xxx pc = &arr;

分析

①首先判斷arr是一個數組數組的每一個元素類型是char*,所以arr是指針數組

&數組名表示整個數組的地址,pc一定是一個數組指針

③既然是數組指針,可以先寫(*pc)表明是一個指針指向的是一個元素為char*類型的數組,一共有五個元素,即char* (*pc)[5] pc = &arr;

????????嘗試使用數組指針遍歷數組每一個元素;這里著重理解:若pc是數組指針,那么*pc是數組名,數組名其實就是數組首元素的地址,所以若需要打印數組元素,這里必須兩次解引用

? ? ? ? 但是正常的人類不會這么來遍歷數組,直接使用一級指針就能完成遍歷的操作,不建議這樣去用

1.?數組指針常見的用法

1.1 作為參數遍歷二維數組:

????????使用數組指針遍歷一維數組確實有些脫褲子放屁,但是使用數組指針卻可以很輕易的遍歷二維數組。

分析

????????3*5的二維數組其實是三個int數組拼接而成,所以我們只需要使用數組指針指向第一行,數組指針+1就會跳轉到下一行,每一行中需要對數組指針解引用,可以獲得一維數組名即一維數組首元素的地址,即類型為int*,此時再加上列j,最后再進行解引用就能獲得每一個元素了。??

??????

1.2 下列是指針還是數組?

 // 指針大全
int main()
{int i = 10;int* p1 = &i;int** p2 = &p1; char arr1[5] = { 0 };// p3,p5等價char* p3 = arr1;char p4 = arr1[0];char* p5 = &arr1[0];int* arr2[5] = { 0 }; char(*p6)[5] = &arr1;  // ?int* (*p7)[5] = &arr2;// ??int(*parr[10])[5];  // ???return 0;
}

? ?答案揭曉:

 // 指針大全
int main()
{int i = 10;int* p1 = &i;int** p2 = &p1; // 二級指針,存放一級指針變量的地址char arr1[5] = { 0 };// p3,p5等價char* p3 = arr1;char p4 = arr1[0];char* p5 = &arr1[0];int* arr2[5] = { 0 }; // 指針數組,每一個元素都是int*類型的char(*p6)[5] = &arr1; // 數組指針,指向數組char arr1[5]int* (*p7)[5] = &arr2;// 數組指針,指向數組int* arr2[5]int(*parr[10])[5]; // parr首先和[]結合,所以這是一個數組,去掉這兩個部分,剩下int (*) [5]是一個數組指針// 所以這是一個可以容納10個數組指針的數組return 0;
}

? ? ? ? 最后一個?int(*parr[10])[5];有些難理解,我們可以采取的策略是:先定性,再去掉,最后判斷

①先定性:parr和【】首先結合,所以這一定是一個數組。

②parr[]去掉。

③判斷剩下的部分:int(*)[5],這很顯然是一個數組指針。

④下結論:這是一個可以存放10個數組指針的數組

2. 數組參數和指針參數

? ? ? ? 寫函數的時候,難免會把指針或者數組名傳遞給參數,我們該如何設計函數呢?

2.1 一維數組傳參

下面的參數正確嗎?

① 正確。一維數組傳參的時候可以不指定數組長度。

②正確。形參和實參一致。

③正確。傳入數組名,本質上就是首元素的地址,每一個元素是int*,可以使用指針接收。

④正確。形參和實參一致。

⑤正確。arr2是一個存放一級指針的數組,直接傳入數組名,就是傳遞首元素的地址,首元素為一級指針,要存放一級指針的地址可以使用二級指針。

2.2 二維數組傳參

下面的參數正確嗎?

①、③正確,②錯誤原因圖中已經標識。

????????二維數組傳入數組名,在之前的例子已經講過了,代表了首元素的地址,而首元素是一個數組,那么就是整個數組的地址,這個數組有五個元素,每一個元素是int類型,這里需要使用數組指針來接收地址。所以只有③正確。

2.3 一級指針傳參

非常簡單,下圖可以直接概括。

2.4 二級指針傳參

①正確。二級指針傳參使用二級指針接受肯定是沒有問題的。

②正確。使用一級指針的地址傳參,當然也是沒有問題的。

反過來想,如果形參使用二級指針,那么實參能傳什么呢?除了剛剛講的前兩種情況,這里可以存儲指針數組名。這是因為指針數組名是數組首元素的地址,首元素是一級指針,換言之也是一級指針的地址。

3.?函數指針介紹

顧名思義指向函數的指針。

????????這要牽扯到如何求函數的地址,我們知道&數組名是取出數組的地址,以此類推,&函數名可以取出函數的地址。

? ? ? ? 如何存放函數的地址呢?這就用到了函數指針,函數指針的定義也非常簡單,首先確定這是一個指針*p,然后在后面加上大括號,確定這是一個函數指針,在大括號里面輸入形參類型,在整個表達式前面標明返回類型。

? ? ? ? 利用函數指針調用函數也就順理成章了,直接解引用之后按照函數的方法直接調用即可。

? ? ? ? 看似這一切都是脫褲子放屁,我為什么不直接調用函數呢?這是因為我們視野所限,后面還有更高級的玩法,例如將函數指針作為函數傳遞傳給另外一個函數......

? ? ? ? 需要注意的一點是,這里的p可以不使用*解引用,因為add本質上是函數的地址,那么p存放的也是函數的地址,如果能夠這樣使用:add(),那么為什么不能這樣使用:p();這里加上*只是為了明確這是一個指針。如果要加上*號,記得要加上括號。

3.1 函數指針的簡單使用

作為另外一個函數的形參,在另外一個函數進行使用。

????????看到這里,你心中仍然覺得這是多此一舉,那我為什么不直接調用呢?其實這涉及到面向對象的內容,試想一下:如果有四個方法,分別是加減乘除的功能,這四個方法除了方法名和方法體不一樣,形參和返回值都是一樣的,這時候我們只需要傳入不同的方法名給這個函數指針,就能實現不同的方法,這就是多態

3.2 函數指針的題目

首先來看一段來自《C陷阱和缺陷》這本書中非常有意思的代碼。

①首先看void(*)(),如果這是void(*p)(),這就是函數指針,此時把變量名去掉,這就是變量的類型;類比int* p去掉p,int* 就是變量的類型一樣。

②整體對這個變量類型大括號,后面再放一個0,這就是將0強制類型轉換為函數指針類型,地址為0的地方存在一個函數,這個函數不需要返回值也不需要形參。

③然后對整體函數指針進行解引用,再進行函數的調用。

總結以上代碼就是一次函數的調用,調用的是0作為地址的函數,這個函數沒有返回值沒有形參

以下是這本書的原話:

? ? ? ? 繼續看一段來自這本書的一段代碼。

分析

①從signal入手,signal首先和()結合,()內部一個是整型類型,一個是函數指針類型,這是函數的聲明,函數的聲明的形參只需要注明形參的類型即可,例如:int add(int,int)。

②將signal(int,void(*)(int))去掉之后,看剩下的部分,void(*)(int),這毫無疑問是聲明函數的返回值

③所以總結一下,這個就是一個函數的聲明,返回值是一個函數指針

我們可以使用typedef簡化一下:如此一來,一眼就能看出這是一個函數聲明。

3.3 函數指針的用途

給出一個需求,計算兩個數字的四則運算。

?

????????我們發現,在swich語句中代碼存在大量冗余,只有一行不一樣,這一行只是調用的方法不一樣,剩下的部分都一樣,我們該如何解決?????????

? ? ? ? 使用函數指針就可以完美解決,創建一個函數,形參是函數指針,根據傳入的具體實參的不同,調用不同的方法,這個其實就是面向對象的多態

回調函數也是這么做的,實現定義好函數指針,適時地進行調用函數。

? ? ? ? 今天的內容就到這了,下一期是最后一期關于指針的內容,如果對你有幫助,可以點贊收藏評論,一鍵三連,你的支持是我更新的最大動力!!?

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

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

相關文章

在HTML中CSS三種使用方式

一、行內樣式在標簽<>中輸入style "屬性&#xff1a;屬性值;"。(中等使用頻率)不利于CSS樣式的復用&#xff1b;違背了CSS內容和樣式分離的設計理念&#xff0c;后期難以維護。<p style"color: red">這是div中的p元素</p>二、內部樣式在…

汽車功能安全-軟件單元驗證 (Software Unit Verification)【用例導出方法、輸出物】8

文章目錄1 軟件單元驗證用例導出方法2 測試用例完整性度量標準3 驗證環境要求4 軟件單元驗證的工作產品1 軟件單元驗證用例導出方法 為確保軟件單元測試的測試案例規范符合9.4.2要求&#xff0c;應通過表8所列方法開發測試用例。 表8 軟件單元測試用例的得出方法&#xff1a; …

MySQL內置函數(8)

文章目錄前言一、日期函數二、字符串函數三、數學函數四、其它函數總結前言 其實在之前的幾篇中我們也用到了內置函數&#xff0c;現在我們再來系統學習一下它&#xff01; 一、日期函數 函數名稱描述current_date()獲取當前日期current_time()獲取當前時間current_timestamp(…

蒼穹外賣項目日記(day04)

蒼穹外賣|項目日記(day04) 前言: 今天主要是接口開發, 涉及的新東西不多, 需要注意的只有多表聯查和修改的邏輯,今日難點: 1.菜品的停起售狀態設置 2.套餐的停起售狀態設置 3.動態sql中的 useGeneratedKeys 與 keyProperty 兩個參數 一. 菜品的停起售狀態設置 ? 在菜品的停售中…

React之旅-05 List Key

每個React的初學者&#xff0c;在調試程序時&#xff0c;都會遇到這樣的警告&#xff1a;Warning: Each child in a list should have a unique "key" prop. 如下面的代碼&#xff1a; const list [Learn React, Learn GraphQL];const ListWithoutKey () > (&l…

[特殊字符] 人工智能技術全景:從基礎理論到前沿應用的深度解析

&#x1f680; 人工智能技術全景&#xff1a;從基礎理論到前沿應用的深度解析 在這個AI驅動的時代&#xff0c;理解人工智能的核心技術和應用場景已成為技術人員的必備技能。本文將帶你深入探索AI的發展脈絡、核心技術差異以及在各行業的創新應用。 文章目錄&#x1f680; 人工…

Go語言教程-環境搭建

前言 Go&#xff08;又稱 Golang&#xff09;是由 Google 開發的一種 開源、靜態類型、編譯型 編程語言&#xff0c;于 2009 年正式發布。它旨在解決現代軟件開發中的高并發、高性能和可維護性問題&#xff0c;尤其適合 云計算、微服務、分布式系統 等領域。 Go 語言國際官網…

windows指定某node及npm版本下載

下載并安裝 nvm-windowshttps://github.com/coreybutler/nvm-windows/releases&#xff08;選擇 nvm-setup.zip&#xff09;。打開命令提示符&#xff08;管理員權限&#xff09;&#xff0c;安裝 Node.js v16.15.0&#xff1a; nvm install 16.15.0 nvm use 16.15.0 驗證node版…

每天一個前端小知識 Day 28 - Web Workers / 多線程模型在前端中的應用實踐

Web Workers / 多線程模型在前端中的應用實踐&#x1f9e0; 一、為什么前端需要多線程&#xff1f; 單線程 JS 的瓶頸&#xff1a;瀏覽器主線程不僅負責執行 JS&#xff0c;還要負責&#xff1a; UI 渲染&#xff08;DOM/CSS&#xff09;用戶事件處理&#xff08;點擊、輸入&am…

python:ImportError: cannot import name ‘ParameterSource‘ from ‘click.core‘

瀏覽器訪問網站拋錯&#xff1a;ImportError: cannot import name ParameterSource from click.core (E:\environment\python\Lib\site-packages\click\core.py)問題分析&#xff1a;1. click 版本問題ParameterSource 可能是在某個特定版本的 click 庫中引入的&#xff0c;而你…

flink 去重

LOCALTIMESTAMP as time_stamp ts as case when time is null then CURRENT_TIMESTAMP else TO_TIMESTAMP_LTZ(time, 0) end , watermark for ts as ts - interval ‘60’ second PARTITION BY 的都有回撤流 group by 的沒有回撤流 因為算的是指標 開窗又慢 SELECT * FROM (…

【音視頻】TS協議解析

參考博客&#xff1a;https://blog.csdn.net/rell336/article/details/38109621?utm_mediumdistribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_sourcedistribute.pc_relevant_t0.none-task-blog-BlogCommendFromMac…

uniapp 日期組件可選擇年月

month-picker 月份選擇器組件 組件介紹 month-picker 是一個用于選擇年月的自定義組件&#xff0c;基于 uni-app 開發&#xff0c;提供了簡潔的月份選擇功能。 解決彈框底部出現底部頁面區域 safe-area屬性設為true時&#xff0c;即可解決這個問題效果如圖功能特點 支持選擇年份…

從真人到數字分身:3D人臉掃描設備在高校數字人建模教學中的應用

在影視、動漫、游戲等數字創意產業蓬勃發展的當下&#xff0c;超寫實虛擬數字人憑借其高度逼真的形象&#xff0c;成為行業關注的焦點。無論是影視特效中栩栩如生的角色&#xff0c;還是游戲里精致的NPC&#xff0c;超寫實虛擬數字人的制作都離不開先進的技術支撐。而3D人臉掃描…

你以為大數據只是存?其實真正的“寶藏”藏在這招里——數據挖掘!

你以為大數據只是存&#xff1f;其實真正的“寶藏”藏在這招里——數據挖掘&#xff01; 曾經我也天真地以為&#xff0c;搞大數據就是會寫幾個SQL、部署個Hadoop集群&#xff0c;結果真到項目現場&#xff0c;甲方爸爸一句&#xff1a;“給我挖掘一下用戶的購買意圖”&#xf…

LeetCode經典題解:128、最長連續序列

“最長連續序列”是一道極具代表性的數組處理問題&#xff0c; 本文將帶你從直觀思路出發&#xff0c;逐步推導出最優解法&#xff0c;并通過場景化記憶技巧掌握核心邏輯。 一、題目描述 題目&#xff1a;給定一個未排序的整數數組 nums&#xff0c;找出數字連續的最長序列&…

電力分析儀的“雙語對話”:CCLinkIE與Modbus TCP的無縫連接

在工業自動化領域&#xff0c;協議兼容性問題如同“方言壁壘”&#xff0c;讓不同品牌、不同系統的設備難以高效協同。對于電力分析儀這類關鍵設備而言&#xff0c;如何打破CCLinkIE與Modbus TCP協議的“語言障礙”&#xff0c;已成為工程師優化系統集成的核心課題。 為何需要協…

暑假復習篇之文本編譯器

一、知識點補充【在此次示例代碼上顯示的關鍵用法】知識點1、JMenuBar&#xff1a;菜單欄的容器&#xff0c;通常添加到JFrame的頂部。關鍵用法&#xff1a;add&#xff1a; 添加菜單到菜單欄2、JMenu&#xff1a;菜單條目&#xff08;“文件” “編輯” 等&#xff09;&#x…

Linux自動化構建工具(一)

&#x1f381;個人主頁&#xff1a;工藤新一 &#x1f50d;系列專欄&#xff1a;C面向對象&#xff08;類和對象篇&#xff09; &#x1f31f;心中的天空之城&#xff0c;終會照亮我前方的路 &#x1f389;歡迎大家點贊&#x1f44d;評論&#x1f4dd;收藏?文章 文章目錄Li…

目標檢測流程圖繪制

目標檢測流程圖繪制作為一個長期科研的苦命人&#xff0c;我一般采用Processon。 一、目標檢測流程圖繪制的 “量身定制” 體驗 Processon 的繪圖元素庫對目標檢測領域極度友好&#xff0c;從基礎模塊到復雜結構都能精準匹配&#xff1a; ??核心組件一鍵調用&#xff1a;在右…