2019.12.11
1.什么是指針以及它的作用
儲存數(shù)據(jù)的內(nèi)存是一串連續(xù)的字節(jié)單元格,如圖
內(nèi)存圖解.png
每一個單元格都有自己的地址,而指針則是用來儲存某個地址的變量
那么我們什么時候需要用到指針呢?下圖作為引例值改變.png
使用函數(shù)返回值可以實現(xiàn)一個值的改變瞬捕,而return只能返回一個值虱疏,改變兩個及以上的值便需要指針地址詳解.png
說明:首地址是指第一個字節(jié)的地址毒涧,其實指針并沒有如圖所示的指向作用,那樣畫方便理解徙邻,指針就是地址排嫌,通過它可以間接訪問或修改所存的地址內(nèi)的值,依圖舉個例子鹃栽,可以將0x100(地址)理解為一個小區(qū)中的房間門牌號躏率,1(所存的值)當(dāng)做租客躯畴,而指針就是保安室(登記有所有門牌號即地址)民鼓,通過保安室可以查到門牌號,再使用一個*即登門拜訪
一個指針?biāo)加每臻g:64位系統(tǒng)占8個蓬抄,32位系統(tǒng)占4個
2.指針的類型
指針的運(yùn)算:指針+i是指指針?biāo)傅刂废蛴乙苿?strong>i*sizeof(所指向的變量類型)
指針之間還可以作減法丰嘉,僅限于數(shù)組內(nèi),作差的結(jié)果是兩個地址間相差的元素個數(shù)
整型指針:int *a
字符指針:char *a
指針數(shù)組:int *a[5],一個大小為5嚷缭,每個元素都是指針
數(shù)組指針:int (*a)[5] 只能指向二維數(shù)組饮亏,且二維數(shù)組中的一維數(shù)組長度為5
如int a[3][5];
?int (*p)[5]=a;
常量指針:指向地址的值不能改變
int a=20,b=30;
int const *p=&a;const(常量)在前
*p=&b;//可以改變指針的指向關(guān)系
指針常量:指向關(guān)系不能變,值可以變
int *const p1=&a;*指針在前
*p1=50;//可以改變里面的值
誰在前誰不變
二級指針:?int**p;里面存的是一個一級指針的地址阅爽,指針本身是有地址的二級指針圖解.png
二級以上的指針如圖類推
指針函數(shù):int *add();?先忽略*路幸,add()是個函數(shù),它的返回類型是int*指針(即地址)
函數(shù)指針:int (*p)(int ,int);?由于()的優(yōu)先級更高付翁,所以無法先忽略*简肴,所以從*開始讀,是一個指針百侧,它指向的類型是一個函數(shù)砰识,函數(shù)的返回類型是整型
函數(shù)名其實是一個指針常量,它指向該函數(shù)代碼的首地址
int minus(a,b);
p=minus;
(*p)(a,b);等價于minus(a,b)
☆補(bǔ)充說明:相信很多初學(xué)指針的小伙伴都有這樣的一個困惑佣渴,指針只能用地址來賦值辫狼,為什么常量字符串可以使用char* name="xiaoming",常量字符串為什么可以這樣賦值辛润,其實啊膨处,真正賦值給name的還是一個地址,雙引號" "做了以下三件事:
1.在內(nèi)存中開辟了一片連續(xù)的空間
2.將常量字符串放進(jìn)去砂竖,并在末尾添加\0
3.最后返回那一片連續(xù)內(nèi)存空間的首地址
所以常量字符串的賦值不需要使用malloc為字符指針分配內(nèi)存空間灵迫,直接使用雙引號即可,這樣的表達(dá)是沒有任何問題的晦溪,這是指針中容易搞混的地方
3.指針和數(shù)組的關(guān)系
1.指針與一維數(shù)組之間可以相互轉(zhuǎn)換瀑粥,數(shù)組名是數(shù)組的首地址,可以直接賦給指針
指針與數(shù)組的轉(zhuǎn)換.png
被注釋掉的輸出結(jié)果一樣
數(shù)組是指針常量三圆,所以不能對首地址進(jìn)行自增(++)或自減(--)運(yùn)算狞换,本質(zhì)上是不能對首地址賦值如a=a+1而*(a+1)則是正確的避咆,數(shù)組地址移動方式和指針是相同的,a+i其實是a+i*sizeof(數(shù)組類型),所以對首地址先進(jìn)行移動修噪,然后再顯示新地址內(nèi)的值
指針移動等同數(shù)組.png
所以其實a[i]等價于*(a+i)
2.數(shù)組指針:數(shù)組指針是二維的查库,(只能說)類似于二級指針,要訪問里面的單個元素黄琼,需要使用**
先定義一個數(shù)組指針
int a[2][3]={{1,2,3},{4,5,6}};int (*p)[3]=a;數(shù)組指針圖解.png
而對p+1則是縱向的移動樊销,移動到4所在地址
數(shù)組指針.png
上圖則是運(yùn)行效果
也可以換一種方式理解為什么需要兩個**:前面提到一維數(shù)組等價于指針,所以二維數(shù)組就相當(dāng)于一維數(shù)組里的元素全是指針脏款,*p訪問到第一個元素還是指針即地址围苫,所以還需要一個*才能訪問到真正的第一個元素
4.動態(tài)分配內(nèi)存
常量區(qū) 常量 const int a=1;程序結(jié)束時釋放
靜態(tài)區(qū) static 直到程序結(jié)束才會被釋放內(nèi)存
靜態(tài)變量只會被初始化一次,生命周期從開始(預(yù)編譯)到程序結(jié)束為止
棧 局部變量 int a=10;作用于代碼塊撤师,出了代碼塊就釋放
堆 自己申請的內(nèi)存(malloc calloc realloc) 必須自己釋放內(nèi)存
為什么需要分配內(nèi)存:
1.存儲的數(shù)據(jù)需要延長生命周期
2.一個指針變量需要存儲數(shù)據(jù)剂府,變量本身只能存地址,不能存數(shù)據(jù)剃盾,需要分配內(nèi)存空間來存儲數(shù)據(jù)腺占,必須為指針變量分配內(nèi)存空間,用malloc,引入stdlib.h
如何分配內(nèi)存
char *name;
name=(char *)malloc(10*sizeof(char));
格式:malloc(需要對應(yīng)數(shù)據(jù)類型空間的數(shù)量*sizeof(對應(yīng)的數(shù)據(jù)類型)),前面需要對其聲明痒谴,(數(shù)據(jù)類型*)
動態(tài)分配內(nèi)存的本質(zhì):malloc函數(shù)在內(nèi)存中申請了一片連續(xù)指定大小的空間單元格衰伯,然后返回那片連續(xù)單元格的首地址
name=(char*)realloc(name,20*sizeofz(char))//重新分配已經(jīng)分配的動態(tài)內(nèi)存
格式:realloc(需要重新分配的指針名,對應(yīng)數(shù)據(jù)類型空間的數(shù)量*sizeof(對應(yīng)的數(shù)據(jù)類型))
為了不浪費空間积蔚,程序結(jié)束之間需要釋放申請的內(nèi)存意鲸,free(name);
以上具體的使用會在實戰(zhàn)篇中體現(xiàn)