? ? ? ? ? ? ? ? ? ???Hi~!這里是奮斗的小羊,很榮幸各位能閱讀我的文章,誠請評論指點,關注+收藏,歡迎歡迎~~? ? ?
????????????????????????💥個人主頁:小羊在奮斗
????????????????????????💥所屬專欄:C語言? ?
????????本系列文章為個人學習筆記,在這里撰寫成文一為鞏固知識,二為同樣是初學者的學友展示一些我的學習過程及心得。文筆、排版拙劣,望見諒。?
? ? ? ? ? ? ????????????????? ? 3、指針變量類型的意義
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 3.1指針的解引用
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 3.2指針 +- 整數
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 3.3void *類型
?????????????????????????????????4、const 變量
????????????????????????????????????????????????4.1const 修飾變量
????????????????????????????????????????????????4.2const 修飾指針變量
3、指針變量類型的意義
? ? ? ? 既然指針變量的大小與類型沒有關系,那為什么還要有不同的指針類型呢?
? ? ? ? 在某些情況下,指針類型還是有很大意義的。
?????????3.1指針的解引用
? ? ? ? 這里來舉一個例子探討指針變量類型的意義。
? ? ? ? 如果對調試還不太熟悉可以看這篇文章 —>?VS調試技巧
? ? ? ? 觀察下面代碼在調試時內存中的變化:?
? ? ? ? 我們先給a賦值為0x11223344(16進制),在內存窗口可以看到,然后再通過*pa將a該為0,可以看到內存中也發生了相應的改變。
? ? ? ? 既然指針變量的大小都是一樣的,與指針的類型沒有關系,那我們用char *類型來接收a的地址按理說應該也可以,而且&a取出來的地址都是首地址(一個內存空間,大小是1個字節),好像沒什么問題。從上面調試的結果來看確實放進去了0x11223344這個值。
????????我們接著調試看一下結果:
? ? ? ? 好像跟我們想的不一樣,執行完 *pa = 0;這條語句后只是把最小的地址(一個內存單元)中的值該為了0。這是為什么呢?
?????????因為,指針類型決定了對指針解引用的時候有多大的權限,也就是一次能操作幾個字節。這就是指針變量類型的意義。比如:char *類型的指針解引用訪問一個字節,int *類型的指針解引用訪問4個字節。
? ? ? ? 3.2指針+-整數
?????????觀察下面的代碼:
? ? ? ? 跟我們想的一樣,&a、pa、pc的值是一樣的,但當我們給&a、pa、pc加一個整數1的時候得到了不一樣的結果,通過觀察,&a和pa的值都增加了4,?而pc的值只增加了1。其中的原因還是和3.1中一樣,我們再來通過下面的圖解釋一下:
? ? ? ? 可以理解為他們走的格數不一樣,一個格子就是一個內存單元也就是1個字節空間,a和pa一個是int類型一個是int *類型,所以它們走4個格子;而pc是char *類型,所以它走1個格子。?
? ? ? ? 減一個整數也是同樣的道理。?
? ? ? ? ?3.3void *類型
? ? ? ? 在指針類型中有一種特殊的類型是 void * 類型的,為無具體類型的指針(泛型指針),這種類型的指針可以用來接收任意類型的地址。但是有一定的局限性,void *類型的指針不能直接進行指針的 +- 整數和解引用運算。了解了上面的內容,這其中的原因相信我們已經心知肚明。
? ? ? ? 其實,我們 char *pc = &a;是有問題的,&a取出的地址畢竟是int *類型。雖然能正常運行,但是編譯器也有相應的警告:
? ? ? ? 但是我們用void *去接受就沒有任何問題:?
? ? ? ? 雖然void *類型的指針不能直接進行解引用操作,也不能 +- 整數的操作,?但是當我們不知道別人給我們傳的地址是什么類型的時候,我們就可以放心地去用void *來接收,這就是它的作用。
? ? ? ? 一般void *類型的指針是使用在函數參數的部分,用來接收不同類型數據的地址,這樣的設計可以實現泛型編程的效果,使得一個函數來處理多種類型的數據。在后面的文章中會深入探討。?
4、const 變量
? ? ? ? 4.1const 修飾變量
? ? ? ? 變量變量,顧名思義就是可以改變的量,當我們創建一個整整變量a并賦初值10:int a = 10;如果我們想改變a的值隨時就可以改,誰讓它是變量呢?
? ? ? ? 那如果我們想訓練一下這個變量a,讓它變得強大,誰都改變不了它,有沒有辦法呢?
? ? ? ? 辦法就是使用const修飾,當我們用const修飾了變量a后,它就擁有了常量的屬性,我們知道常量是不能被改變的量。
? ? ? ? 當變量a被const “訓練” 過后,我們再試圖去改變它的值,就會發現編譯器報錯,說a是不可被修改的,變量a得到了 “強化”。
????????但是const修飾的變量本質上還是變量,只是不能被修改。我們也可以用例子證明這句話:
? ? ? ??前面的文章中我們說過,創建數組的時候數組長度只能為大于0的整型常量或整型常量表達式,不能包含變量。所以上面的例子就證明了變量a即使被const修飾,具有了常量屬性,但本質還是變量。
? ? ? ? 4.2const 修飾指針變量
? ? ? ? 看了上面的內容,我們可能會有一個想法。
? ? ? ? 在4.1中,const修飾變量a后,我們就不能改變a的值了,但上面我們只是直接去改發現改不了,那間接地去改呢?因為上篇文章我們剛了解了一點指針,知道通過指針的解引用操作可以間接地去找到、操作一些值,那這里能不能創建一個指針變量pa,將變量a的地址存到pa中,再解引用pa來實現間接改變a的值呢?
? ? ? ? 來實驗一下我們的想法:
? ? ? ? ?可以看到,我們的想法是有道理的,通過指針的解引用操作確實間接地改變了a的值。?
?????????但是,但是,這樣做其實是不對的。這就像門被鎖了翻窗戶一樣,鎖門的目的就是為了不讓別人進得去房間,我們還為了進去而翻窗戶,肯定是不合規矩的。為什么要有const呢?不就是為了讓變量具有常屬性不能被改變嘛,那我們還去改變它就顯得沒事找事了。
? ? ? ? 不過,雖然大多數的人都是守法公民,但還是有個別不聽勸的,非要 “翻窗戶”,那有沒有辦法解決呢?答案肯定是有的,因為我們不能容忍任何一個人不 “遵紀守法”。
? ? ? ? 既然指針的解引用可以間接地去改變const修飾的變量的值,那我們干脆把指針變量也用const修飾,因為指針變量也是變量嘛。
? ? ? ? const修飾指針變量時,const可以放到 “ * ” 的左邊也可以放到 “ * ” 的右邊,這樣就會產生三種情況(其中前兩種情況的效果是一樣的):
? ? ? ? const 放在?“ * ” 的左邊:
? ? ? ? 可以看到,當我們改變 *pa (也就是改變a)的值的時候,編譯器提示錯誤,但改變 pa 的值是可以的。所以,當const在 “ * ” 左邊的時候修飾的是*pa ,這時候*pa具有常量屬性。
? ? ? ? 上面代碼中改變pa的值事實上是改變了指針變量pa的指向,也就是此時指針變量pa里面存的是變量b的地址。
? ? ? ? const 放在 “ * ” 的右邊:
? ? ? ? 可以看到,當const在 “ * ” 右邊的時候,改變*pa的值是可以的,但改變指針變量pa的指向,也就是改變指針變量pa里存的地址是不可行的。?所以,當const在 “ * ” 右邊的時候修飾的是pa,這時候pa具有常量屬性。
? ? ? ? 還有,當 “ * ” 的左邊和右邊都有const修飾的時候,*pa和pa都具有常量屬性,都不能改變。
????????如果覺得我的文章還不錯,請點贊、收藏 + 關注支持一下,我會持續更新更好的文章。
????????????????????????????????????????? 點擊跳轉下一節 —>?C語言(指針)3