C語言教程(5)之指標
指標:(C語言的靈魂)
記憶體的儲存是以一個位元組為一個編號,也就是8位合在一起給一個編號,不是0,1就給編號。
記憶體分為很多個單元,每個單元就會分配一個編號。
地址:記憶體單元的一個編號。而指標和地址一個概念的。也就是說指標就是地址。
普通變數:只能存放一個值。
指標變數:同樣是一個變數,但是指標變數存放其他變數的地址。
*p代表的是p所指向的那個變數。在上圖中*p和i是同一個東西,但是*p和p不是同一個東西。
在上圖中,int * p是一個宣告,開頭的int * 是他的資料型別。P是變數的名字。不能理解我定義了一個整形變數,這個整形變數的名字叫做*p。所謂int *型別
*p代表的是以p的內容為地址的變數。
解析:p的內容是一個地址,在上圖中,p的內容就是i的地址,*p其指向的變數當然就是i變量了。
指標和指標變數:
指標就是地址,地址就是指標。
地址就是記憶體單元的編號。
指標變數:存放地址的變數。而指標只是一個值,這個值是記憶體單元的一個編號。指標變數才是一個變數,他裡面才可以存放資料。
指標和指標變數是兩個不同的概念,但是需要注意的是,通常我們在敘述時會把指標變數簡稱為指標,實際他們含義並不一樣。
指標的重要性:
指標的分類:
指標的定義:
·地址:記憶體單元的編號,是一個從0開始的非負整數。
範圍:cpu對記憶體是通過控制、資料、地址三條匯流排來進行控制的。
控制:cup會先把記憶體中的資料讀入,進行處理後,在返回給記憶體,然後記憶體在把資料寫入硬碟。
資料:用於資料的傳輸,不管是把記憶體中的資料傳送給cpu,還是把cpu的資料寫如記憶體條,都是由資料線來完成的,但是資料傳輸的方向則是由控制線來控制的。
地址:地址線則是確定資料要寫入記憶體中的那個單元。
所謂的一個單元就是一個位元組。
一條地址匯流排能控制2的1次方,一般的機器有32個地址線,最終能夠控制2的32個單元,而每個單元是八位,而最終我們的記憶體能夠儲存2的32次方*8位。
則換算為G的話,最終大小為4G.那麼地址匯流排的範圍則是4G大。
指標:指標就是地址,地址就是指標。
指標變數就是存放記憶體單元編號的變數。
指標變數和指標是兩個不同的概念。
指標的本質就是一個操作受限的非負整數。
指標不能進行算術運算-相加 乘 除。但是能相減。
如果兩個指標變數指向的是同一塊連續空間的不同儲存單元,則這兩個指標變數才可以相減。類似於同一個小區同一樓層六牌號相減表示兩房間隔。這時才有現實意義。
基本型別的指標:
Int *p:p只能存放int型別的地址。
P = & i:把i的地址賦給p。然後p就指向了i,*p就等於i。其實就是
1:該語句儲存了i的地址。
2:p儲存了i的地址,所以p指向i。
3:p既然指向i,*p就是i。
*p:表示以p的內容為地址的變數。
*p:p是有指向的,p裡面是個垃圾值,*p則是說以p的內容為地址的變數。因為不知道p的值是多少,所以不知道*p到底代表的是那個變數。而*p = i,i=5,最終的結果就是把5賦給了一個所不知道的單元。
上圖中,第一個error是資料型別不符合,不能相互轉
換。*q代表的是整形,因為*q代表的是以q的地址為內容的變數。而p是地址(int *)型別。第二個error
同樣有錯,因為q沒有賦值。
經典指標程式-互換兩個數字:
1:先用函式來互換:
最終的輸出結果沒有互換,因為函式的a,b已經執行
完成,分配給記憶體的空間已經釋放了,所以最終a,b
的值還是主函式a,b的值。互換的是形參的a,b。和
主函式沒有關係。
在上圖中,輸出的值也是沒有互換的,輸出的同樣是3
,5,需要注意的是,互換的只是p、q的內容,區域性函式變化了,但是主函式是沒有變化的。
最終正確的程式:
*號的三種含義:
1:乘法
2:定義指標變數。Int * p,定義了一個名字叫p的變
量,int *表示p只能存放int變數的地址。
3:指標運算子。該運算子是放在已經定義好的指標變
量的前面。如果p是一個已經定義好的指標變數,則*
P表示以p的內容為地址的變數。
注意理解形參,實參,和區域性變數的關係。
指標可以是函式返回一個以上的值:
不使用指標的話,只能使用用return來返回一個值。
如何通過被調函式修改主調函式普通變數的值
指標和陣列:
指標和一維陣列:
(陣列名 下標與指標關係 指標變數的運算)
·一維陣列名:一維陣列名是個指標常量,他存放的是
一維陣列第一個元素的地址。
常量是不能被改變的,也就是說,一維陣列名是不能被
改變的。
陣列名a存放的是一維陣列第一個元素的地址,也就是
a = &a。
printf(“%#X\n”,&a[0]); ===== printf(“%#X\n”,a);
指標和二維陣列:
下標和指標的關係:
·如果p是個指標變數,則p[i]永遠等價於*(p+i)
確定一個一維陣列需要幾個引數,【如果一個函式要處理一個一維陣列,則形參需要接收該陣列的哪些資訊。】
確定一個一維陣列需要兩個引數,
1:陣列名,從陣列的名稱就可以知道陣列的第一個值,因為一維陣列的名稱就是陣列的第一個元素的地址。
2:是陣列的個數。來計算該陣列有多少個值。
區別於 字串(只需要一個引數—首地址)
因為字串預設其後面都有一個“/0”作為結束標誌。而陣列並沒有相關約定。
在上圖中,a是個指標變數,所以上面區域性函式f的pArr則要定義成指標函式才可以,而len則是int型別。代表接收的是整型的數字。
在上圖中因為陣列a的名稱代表的是a的第一個元素的地址,所以在函式f中所定義的指標變數pArr和a是相同的,因為a也是指標型別。也就是說pArr=a=a[0],pArr[1]=a[1]=*(pArr+1)=*(a+1),pArr[2]=a[2]=*(pArr+2) =*(a+2).所以在f函式中pArr[3]=a[3],所以第二個printf輸出的結果是88.
總結:pArr[i] = a[i] = *(pArr+i) = *(a+i)
在沒有學習指標時,可將a[3]認為是陣列中第4個元素,但現在應該對其內部原理有更深刻認識。
這裡下標也當成指標了,從首元素開始向後移動3個,即指向第4個元素。
在上圖中因為陣列a的名稱代表的是a的第一個元素的地址,所以在函式f中所定義的指標變數pArr和a是相同的,因為a也是指標變數型別。也就是說pArr=a=a[0],pArr[1]=a[1]=*(pArr+1)=*(a+1),pArr[2]=a[2]=*(pArr+2) =*(a+2).
通過上圖,我們知道,我們在f函式中修改陣列的值,相當於修改主函式中相對應的值。
何謂變數地址 / 一個指標佔幾個位元組
Sizeof(變數名/資料型別) 其返回值就是該變數或資料型別所佔位元組數。
一個指標變數無論其指向變數佔幾個位元組,其本身所佔大小都是4位元組。
*p具體指向幾個位元組,要靠前面型別確定,如果為int則為4位元組,如果double則佔8位元組。
CPU 與 記憶體 互動時 有32根線,每根線只能是1或0兩個狀態,所有總共有232個狀態。
1 個狀態 對應 一個單元。如全為0 全為1 等。
記憶體中第一個單元,即32根線狀態全為0。
0000 0000 0000 0000 0000 0000 0000 0000
其大小為4位元組
所有每個地址(硬體所能訪問)的用4個位元組儲存(而不是一 位bit)
一個變數的地址—用該變數首位元組的地址表示。這也就是為什麼指標變數始終只佔4位元組的原因。