主頁 > 軟體設計 > C語言指標全歸納-進階版

C語言指標全歸納-進階版

2021-04-05 10:43:04 軟體設計

進階的內容比較龐大,但請各位耐心看完,我相信一定會有所識訓,如果我有錯誤的地方希望大家可以指正我的錯誤,萬分感謝

防止有些博友沒有看過前一篇我的博客,在此簡單概括一下那篇博客的內容有哪些,

  1. 指標變數是用來存放地址的,對其解參考就可以找到該地址唯一標識的記憶體空間
  2. 指標大小在32位平臺上為4位元組,在64位平臺上為8位元組
  3. 指標具有型別之分,指標型別決定了其進行解參考操作時的訪問權限及+/-整數的步幅
  4. 指標的幾種運算(指標加減整數,指標減指標,指標關系運算)

本文章主要內容

  • 1.字符指標
  • 2.指標陣列
  • 3.陣列指標
  • 4.陣列傳參和指標傳參
  • 5.函式指標
  • 6.函式指標陣列
  • 7.指向函式指標陣列的指標
  • 8.回呼函式

1.字符指標

我們知道字符指標的使用方法為

#include<stdio.h>
int main()
{
    char a='0';
    char *p=&a;
    *p='a';
    return 0;
}

那下面這種是什么意思呢

#include<stdio.h>
int main()
{
    char *p="Thanks for browsing";
    return 0;
}

我們知道char*只能存一個元素的地址,但怎么可以和一個字串相等呢?
在這里插入圖片描述

有次我們看到,原來上面這個代碼的意思是存放該字串首元素的地址(即‘T’的地址存放在p中)
那么我們就可以這樣使用它了
在這里插入圖片描述
但是這樣寫有個小問題,這里的"Thanks for browsing"和存放于陣列中的字串不同,是不可更改的,被稱為常量字串,它在記憶體里只會存盤一份,
不理解只存一份的可以點我哦

2.指標陣列

初階已介紹指標陣列,即存放指標的陣列就是指標陣列
在此就不再贅述,主要是為了區分下面的陣列指標

int *arr1[10];//存放一級整形指標的陣列
int **arr2[10];//存放二級整形指標的陣列

3.陣列指標

陣列指標重點說的是指標
例如整形指標是指向整形的指標、字符指標是指向字符的指標
那么陣列指標就是指向陣列的指標

int arr[10]={0};
int (*p1)[10]=&arr;
int *p2=arr;
//*p代表這是個指標,因為[]比*的結合性要高,會與指標陣列產生歧義,所以需要加上()
//即int (*p1)[10]=&arr的完整解釋為p是一個指向有十個整形元素的指標

&arr是指整個陣列的首地址
arr是指首元素的地址
兩者雖數值上相同,但加1后移動的步幅不同!(如下圖)


陣列名只有在兩種情況下是指整個陣列的首地址

  1. &arr
  2. sizeof(arr)

除此之外陣列名均指代陣列首元素地址

接下來我們來介紹一下陣列指標的使用方法

#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	int i = 0;
	int(*p)[10] = &arr;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", (*p)[i]);
		printf("%d ", *((*p)+i));
		printf("%d ", (*p)[0][i]);
		//以上三種均可找到陣列中的元素
		//*p等價于arr,即arr[i]==(*p)[i]
		//&具有‘升維’的作用,*具有‘降維’的作用
	}
	return 0;
}

在這里插入圖片描述

#include<stdio.h>
void print(int (*p)[5],int r,int c)
{
	int i = 0;
	for (i = 0; i < r; i++)
	{
		int j = 0;
		for (j = 0; j < c;j++)
		{
			printf("%d   ", *(*(p+i)+j));
			//p+i相當于&arr+i  第i行的地址
			//*(p+i)+j相當于arr+j  第j個的地址
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][5] = { { 1, 2, 3, 4, 5 },
					{ 6, 7, 8, 9, 10 },
					{ 11, 12, 13, 14, 15 } };
	print(arr, 3, 5);//二維陣列傳參,傳的是第一行的地址
	//傳引數也會發生降維
	//傳二維陣列,函式得到的為第一行的地址
	//傳一維陣列,函式得到的為首元素地址
	return 0;
}

這里做一個小練習,可以測驗一下自己是否真的明白了指標陣列和陣列指標

int arr[5];                 有五個整形元素的陣列
int *p[5];                  有五個整形指標的陣列
int (*p)[5];                指向有五個整形元素的陣列的指標
int (*p[5])[10];            存放五個指向有十個整形元素的陣列的指標的陣列 
//p先和[]結合成為陣列,然后拆解為int (*)[10],
//現在即使陣列中的元素型別,每個元素為指向有十個整形元素的陣列指標         

4.陣列傳參和指標傳參

一維陣列傳參
void test1(int arr[])
{}//該方法就是普通的陣列傳參
void test2(int arr[10])
{}//該方法與test1相同,10并沒有實際意義,只是形式上感覺上下匹配
void test3(int *p)
{}//該方法就是利用了陣列傳參會發生降維,就利用整形指標接收
void test4(int *p[10])
{}//同test2
void test5(int **p)
{}//傳的元素為一級指標,所以可以用二級指標接收
int main()
{
	int arr[10] = { 0 };
	int *p[10] = { 0 };
	test1(arr);
	test2(arr);
	test3(arr); 
	test4(p); 
	test5(p);
	return 0;
}
二維陣列傳參
void test1(int arr[3][5])
{}//該方式可行
void test2(int arr[][5])
{}//該方法可行
void test3(int arr[][])
{}//該方法不可行,對二維陣列而言,可以不知道行數,但必須知道列數
void test4(int *arr)
{}//該方法不可行經降維后得到是一維陣列的地址,而此處卻用整形指標接收
void test5(int* arr[])
{}//該方法不可行,這里用的是指標陣列接收,要想用陣列接收只能用上面兩種
void test6(int (*p)[5])
{}//該方法可行,利用陣列指標指向一個一維陣列
void test7(int **p)
{}//該方法不可行,該方法是為了接收一級指標,利用指標接收只能用上面這種
int main()
{
	int arr[3][5] = { 0 };
	test1(arr);
	test2(arr);
	test3(arr);
	test4(arr);
	test5(arr);
	test6(arr);
	test7(arr);
	return 0;
}
我們知道一級指標傳值,可以用一級指標接收
那么,反過來想想,都有哪些傳過去可以用指標接收呢?
void test(int *p)
{}
int main()
{
	int a = 10;
	int *pa = &a;
	int arr[5] = { 0 };
	test(&a);
	test(pa);
	test(arr);
	//傳參基本原則:傳過去的引數和形參型別相同
	return 0;
}
同理,二級指標呢?
void test(int **p)
{}
int main()
{
	int a = 10;
	int *pa = &a;
	int **ppa = &pa;
	int *arr[10] = { 0 };
	test(ppa);
	test(&pa);
	test(arr);
	return 0;
}

5.函式指標

#include<stdio.h>
int test(int x,int y)
{return x*y;}
int main()
{
	int a=0;
	int *pa=&a;//指向整形的指標
	
	int arr[10]={0};
	int (*parr)[10]=&arr;//指向陣列的指標

	int    (*pf)(int ,int)=&test;//指向函式的指標
//函式回傳值型別   引數型別   函式名取地址即可獲得函式地址
test==&test 兩者相同,上面可替換,這里可沒有函式首元素一說
     函式指標如何呼叫函式呢?
    int b=(*pf)(2,3);//和正常使用指標是類似的,只需解參考即可使用
    return 0;
}

但上面已經寫過,將test賦給pf,那么是否意味著pf也可以和test一樣直接呼叫函式呢?
答案是肯定的,可以,pf前面加星號是為了初學者可以更快了解C語言語法,其實 并未起到解參考的用處,但如果寫成(pf)(2,3)的形式就一定要帶括號,否則意思就變成了對呼叫函式的結果解參考
在這里插入圖片描述
現在我們已經初步認識函式指標,接下來我們來看看兩句很“有趣”的代碼

1.(*(void(*)())0)()
  1. 這個的確很不好看明白,但首先我們知道void(*)()是一個不需要引數且回傳值為空的函式指標型別,而 ()0就是將0強制型別轉換為函式指標型別,接著就是解參考呼叫0地址處的函式,該函式無引數,回傳型別為void,
    (該代碼源自C陷阱和缺陷)
    該圖片源自C陷阱和缺陷
2.void(* signal(int, void(*)(int) ) )(int);
  1. 首先要肯定的是這是一個函式宣告,signal是函式名,需要整形和函式指標(該函式指標引數為int,回傳值型別為void)兩個引數,signal的回傳值型別為void(* )(int)(該函式指標引數為int,回傳值型別為void),
上面這個其實不容易理解,所以我們可以利用typedef讓它變得好看一點
typedef void(*new_pf)(int) ;
注意new_pf為新名字,void(*)(int)為舊名字
這樣寫是語法規定,不可以寫成typedef void(*)(int) new_pf;
所以上面的函式宣告就可以寫成  new_pf signal(int,new_pf);

6.函式指標陣列

這個應該可以舉一反三了吧,函式指標陣列即存放函式指標的陣列

#include<stdio.h>
void test1()
{
	printf("hello\n");
}
void test2()
{
	printf("world\n");
}
int main()
{
	void(*pt1)() = test1;
	void(*pt2)() = test2;
	void(*parr[2])() = (test1, test2);
	//函式指標陣列其實就是在函式指標的名字后面加 [元素個數]
	return 0;
}

運用函式指標陣列很經典的案例函式指標陣列實作計算器(可以點進來了解一下)

7.指向函式指標陣列的指標

函式指標陣列終歸是個陣列,既然是陣列,那就可以用指標指向它

int (*p)(int ,int);//函式指標
int (*parr[5])(int ,int);//函式指標陣列
int (*(*pparr)[5])(int ,int)= &parr;//指向函式指標陣列的指標
(*pparr)證明是個指標,[5]說明指向的是個陣列,元素型別為int (*)(int ,int)

8.回呼函式

注意重點來了

回呼函式就是一個通過函式指標呼叫的函式,如果你把函式的指標(地址)作為引數傳遞給另一個函式,當這個指標被用來呼叫其所指向的函式時,我們就說這是回呼函式,回呼函式不是由該函式的實作方直接呼叫,而是在特定的事件或條件發生時由另外的一方呼叫的,用于對該事件或條件進行相應,

舉個例子
void test1()
{
     printf("hello");
}
void test2(void (*p)())
{
	 p();
}
int main()
{
    test2(test1);
    并沒有主動呼叫test1,而是將test1地址傳給test2,在適當情況下test2呼叫test1
    此時test1被稱為回呼函式
    return 0;
}

如果想加深一下對回呼函式的理解可以點下面兩個鏈接
回呼函式計算器
快速排序的使用(qsort就是一個很好的回呼函式)

大家好,上次的初階版讓我第一次感受到了寫博客喜悅,原來可以有這么多人看我的博客呀,非常感謝大家對我的支持與鼓勵,我一定會再接再厲,繼續創作出優質的內容來向大家分享知識,——2021.3.23

今天終于把它磨出來了,雖然有些小細節還是可能還需更改,但內容上還是很充實的,非常感謝點進來的每個人,——2021.4.4

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/272539.html

標籤:其他

上一篇:Java基礎知識之資料型別和運算子詳解

下一篇:從0到1實戰微服務架構

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more