C語言中的指針以及二級指針代碼詳解
很多初學(xué)者都對C中的指針很迷糊,希望這篇blog能幫助到大家:
1.什么是“指針”:
在執(zhí)行C程序的時(shí)候,由于我們的數(shù)據(jù)是存儲(chǔ)在內(nèi)存中的。所以對于C程序本身來說,如果想找到相應(yīng)被調(diào)用的數(shù)據(jù),就要知道存儲(chǔ)該數(shù)據(jù)的內(nèi)存地址是多少,換言之,C程序通過已知的內(nèi)存地址到相應(yīng)的內(nèi)存位置存儲(chǔ)數(shù)據(jù)。
這里簡單說一下內(nèi)存管理(對于初學(xué)者來說。為了避免專業(yè)術(shù)語引發(fā)的理解問題,下面的敘述盡量避免專業(yè)定義:),對于現(xiàn)代計(jì)算機(jī)系統(tǒng)來說,內(nèi)存空間分為兩個(gè)區(qū)域,一個(gè)是“數(shù)據(jù)區(qū)”,一個(gè)是“地址區(qū)”,“數(shù)據(jù)區(qū)”存儲(chǔ)的是用戶數(shù)據(jù),比如我們要把一個(gè)數(shù)字“5”存儲(chǔ)到計(jì)算機(jī)(因?yàn)橐粋€(gè)單純的自然數(shù)“5”,是沒有任何意義的,然后對于計(jì)算機(jī)來說它需要知道你要把什么定義為“5”,你就不得不定義“x=5")對于計(jì)算機(jī)而言,這個(gè)過程分為以下幾個(gè)部分:
1.在”棧區(qū)(stack)(這個(gè)定義實(shí)在不能避免,初學(xué)者的話就請暫時(shí)記住這個(gè)名字)“開辟一個(gè)空間,用來存放”5“
2.另存存放”5“的內(nèi)存的地址。
3.將步驟2中的內(nèi)存地址存在另一個(gè)區(qū)域(專門用來存放地址的指針區(qū)),并記下當(dāng)前存放步驟2中的內(nèi)存地址的內(nèi)存地址(好拗口,這里其實(shí)是二級指針的概念)
3.建立一個(gè)”索引“將x與步驟3中的內(nèi)存地址關(guān)聯(lián),存放在”索引區(qū)“(請注意,x和5不是存在一起的,而是有一個(gè)“映射表”,并且 指向 x的指針不會(huì)直接指向5,而是直接指向x,再通過“映射表”找到x的值‘5',這個(gè)概念非常重要,后面例子會(huì)講到利用指針交換兩個(gè)變量的值,就是基于“x和5不是存在一起的”這個(gè)基本概念)。
這里再多說一嘴:為什么要以這種方式存放數(shù)據(jù)?
內(nèi)存的存儲(chǔ)區(qū)就像一池湖水,數(shù)據(jù)就像池水里面的魚,如果不用內(nèi)存尋址的方式,那么當(dāng)你找某個(gè)特定數(shù)據(jù)的時(shí)候,就相當(dāng)于在一池湖水里找某一條叫做“張三”的魚一樣--你得一條一條撈出來辨認(rèn)。
如果有內(nèi)存尋址,就像把一池湖水用漁網(wǎng)分成若干網(wǎng)格,每個(gè)網(wǎng)格里面放一兩條魚并且把每個(gè)網(wǎng)格都編號(編號和魚的對應(yīng)關(guān)系假如你用一個(gè)小本子記起來),這樣當(dāng)你想找某條叫“張三“的魚時(shí),你只要打開小本子(指針地址)找相應(yīng)的網(wǎng)格就可以了。
那么,存儲(chǔ)數(shù)據(jù)的內(nèi)存地址(有點(diǎn)拗口)或者說是上面例子里面記載編號和魚的對應(yīng)關(guān)系的小本子就叫指針。
舉個(gè)實(shí)例吧,如下圖所示,我們將內(nèi)存存儲(chǔ)空間實(shí)體化:假設(shè)途中兩條平行線夾的空間是內(nèi)存可以存儲(chǔ)數(shù)據(jù)的空間,途中C的位置存儲(chǔ)的是數(shù)據(jù),那么P的位置存儲(chǔ)的就是指針。
如何定義指針?
int *p;
注意:
1.這里的int,指的是指針p對應(yīng)的存儲(chǔ)區(qū)的數(shù)據(jù)格式,并不是指針p的數(shù)據(jù)格式。你可以理解為指針的數(shù)據(jù)格式只有一種。
2.*不僅僅是單純的運(yùn)算符,它還是聲明符??梢园选?”理解為像“int,float,double”等等這樣的格式聲明。
3.在使用指針p的時(shí)候,經(jīng)常會(huì)用到地址運(yùn)算符“&”,請注意“&”是運(yùn)算符,運(yùn)算操作是取地址,可以把p直接賦上一個(gè)地址值:
int i=5,*p; p=&i;
于是 *p 的值就是5了。
上面還可以這么寫
int i=5; int *p=&i;
從這兩個(gè)例子的區(qū)別可以看出“*”具有類型聲明的作用。
再寫一個(gè)交換兩個(gè)變量的值的代碼:
#include <stdio.h> void swap(int *a, int *b) { int temp;//創(chuàng)建一個(gè)中間變量用于交換位置。 temp = *a; *a = *b; *b = temp; } int main() { int m=10,n=22; swap(&m,&n);//這里對于理解內(nèi)存管理原則非常重要,正如前面所說,變量m和其值10不是存在一個(gè)內(nèi)存存儲(chǔ)區(qū),而是兩個(gè),它們通過一個(gè)映射表映射起來,所以在這里交換m和n的地址值可以理解為交換了m和n的映射表指向位置。 printf("m=%d,n=%d\n",m,n); return 1; }
上面是通過改變兩個(gè)變量地址的方式交換了變量m,n的值。在這個(gè)過程用到了內(nèi)存地址和內(nèi)存以及指針的定義,如果沒有看懂請回頭再仔細(xì)研究指針的定義。
二級指針:
如果你熟悉了指針的定義,那么二級指針應(yīng)該很好理解,所謂的二級指針,就是指針的指針。
具體解釋一下:因?yàn)槿魏我粋€(gè)變量值(包括指針地址)最后都是要放入到內(nèi)存中去的,回到之前舉的“池子里的魚”那個(gè)例子,所謂的二級指針就是存放那個(gè)寫著網(wǎng)格和編號的小本子的位置信息(比如你把這個(gè)本子放到某個(gè)抽屜里了,那么二級指針記載的內(nèi)容就是“如何找到這個(gè)抽屜”)。
二級指針的定義也很簡單粗暴,一個(gè)指針變量 *p存放這個(gè)指針變量地址的二級指針就是 *(*p),你可以直接簡單粗暴地簡寫為**p(編譯器是認(rèn)這個(gè)的)。
其他問題:
1.定義一個(gè)指針變量*p,那么p到底是什么?
你可以簡單粗暴地把的值p理解為 這個(gè)指針變量存儲(chǔ)的地址。切記千萬不要寫成:
int *p=5;
原因就是我之前說過的,這里再重復(fù)一次:*p 只是聲明變量p存儲(chǔ)的內(nèi)容是地址。*p并不是一個(gè)可以賦值的變量,而是一個(gè)”特殊的“ 類型定義+變量。
2.該如何在指針中賦值?
下面說幾個(gè)合法的賦值:
int *temp = *p;//這是二級指針常用的操作,作用是將指針P的值(指針p的值是地址值,指向的是另外一個(gè)地址空間)賦給指針temp指向的值,等價(jià)于 int *temp;temp=*p;
int i=115,j=116,*r=&i,*s=&j;//將i的地址賦給 r</span>
3.對指針的定義迷糊?
你是不是很奇怪:
int i=5,j=6, *a=&i,*b=&j;
在這里 *a=&i,*b=j是可以的,但是如果你這么寫:
int i=5,j=6,*a,*b; *a=&i,*b=j;
這個(gè)時(shí)候 *a=&i,*b=j就要報(bào)錯(cuò)。
為什么?
原因就是我之前說的:你不可以把在 ”int float這樣的格式聲明后的“”*“理解成為運(yùn)算符,而是要理解成為一個(gè)像”int“這樣的格式聲明?!眎nt *a,double * n,float *c“這樣的搭配含義是”a/b/c是一個(gè)指向int/double/float的指針,諸如 int *a=&i這樣的聲明實(shí)際上是 (int *)a=&i。請一定記住這個(gè)特殊情況,這樣你就不會(huì)再迷糊。
4.謹(jǐn)記*a中的*是取(指針a指向的)值運(yùn)算,&b是?。╞所在的內(nèi)存的)地址運(yùn)算。在這里字符a存儲(chǔ)的是地址,而b存儲(chǔ)的是數(shù)據(jù),這里再次聲明,一定不要被3中提出的“特殊情況”搞混,那只是一個(gè)特例,其他情況不可以那樣用。
總結(jié)
以上就是本文關(guān)于C語言中的指針以及二級指針代碼詳解的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
相關(guān)文章
深入了解C語言的動(dòng)態(tài)內(nèi)存管理
所謂動(dòng)態(tài)和靜態(tài)就是指內(nèi)存的分配方式。動(dòng)態(tài)內(nèi)存是指在堆上分配的內(nèi)存,而靜態(tài)內(nèi)存是指在棧上分配的內(nèi)存,本文將用5600字帶你深入了解動(dòng)態(tài)內(nèi)存管理,感興趣的可以學(xué)習(xí)一下2022-07-07QML中動(dòng)態(tài)與靜態(tài)模型應(yīng)用詳解
QML是一種描述性的腳本語言,文件格式以.qml結(jié)尾。語法格式非常像CSS(參考后文具體例子),但又支持javascript形式的編程控制。QtDesigner可以設(shè)計(jì)出·ui界面文件,但是不支持和Qt原生C++代碼的交互2022-08-08C++程序的五大內(nèi)存分區(qū)實(shí)例詳解
C++內(nèi)存區(qū)域,一般可分為棧內(nèi)存區(qū)、堆內(nèi)存區(qū)、全局/靜態(tài)內(nèi)存區(qū)、文字常量內(nèi)存區(qū)及程序代碼區(qū)5大分區(qū),本文就帶大家深刻的理解這5大內(nèi)存分區(qū),感興趣的可以了解一下2021-10-10