?
目錄
?1. 指針變量為什么要有類型?
2. 野指針
2.1 未初始化導致的野指針
2.2 指針越界導致的野指針
2.3 如何規避野指針?
3. 指針運算
3.1 指針加減整數
3.2 指針減指針
3.3 指針的關系運算
4. 二級指針
5. 指針數組
5.1 如何使用指針數組模擬二維數組
????????上一期已經解釋了指針和指針變量的區別以及含義,這一期我們來具體了解一下指針到底有什么作用。
?1. 指針變量為什么要有類型?
? ? ? ? 我們知道指針變量的大小是根據所在平臺決定的,若平臺是32位即x86環境,則指針變量是4個字節,若平臺是64位,則指針變量是8個字節。既然指針變量不會根據指針類型變化,那么我們為什么要區分指針變量的類型呢?換句話說char* 和 int* 都有能力存儲4個字節的地址,為什么不統一成一個自定義的指針變量例如ptr* ?
????????從上圖可以得知,我們把int*類型的地址強行賦給char*類型的地址,再進行取值調用的時候,會根據char*來進行賦值,以至于只會將一個字節賦值成0,若是正常使用int*來接收,那么四個字節都是0 ,如下圖所示。
????????由下圖可知,雖然不同指針變量的存儲類型不影響地址的存儲,但是當直接對地址進行運算,還是會根據指針類型的不同進行運算。char*類型+1,跳過1個字節,int*類型+1,跳過4個字節。
所以我們會得到這樣的結論:指針變量的類型在存取地址的時候可有可無,在修改地址指向的內容的時候是非常有必要的,它決定了在利用地址更改值的時候需要更改多少個字節;若直接對地址進行運算,那么會根據指針變量的類型+‘1’,這個‘1’可能是char類型的一個字節,也可能是int類型的四個字節。?
使用float*和int*的時候,無論是訪問內存還是使用內存,都是4個字節,那么可不可以混用呢?
答案是:不可以。
下圖是整型解引用賦值整型,我們可以看到100以16進制存入內存。
我們把100.0存入內存,發現內存存的數據發生了變化, 雖然都是100,但是浮點數存入內存的方式是不同的。
2. 野指針
? ? ? ? 指針指向的內存沒有初始化,或者已經被銷毀,此時的指針稱為野指針。
2.1 未初始化導致的野指針
2.2 指針越界導致的野指針
2.3 如何規避野指針?
①指針初始化。
②指針小心越界。
③指針指向的空間置為NULL。NULL是0,類型是void*,如果取值的話一定會報錯(默認0地址不能訪問),所以,我們可以先判斷這個指針如果不是NULL再進行取值。
④避免返回局部變量的地址,因為局部變量已經被銷毀了(沒有那塊內存空間的使用權限了)。
⑤指針使用之前檢查有效性。
3. 指針運算
3.1 指針加減整數
這里的values[N_VALUES]并不算下標越界,因為并沒有使用這段內存,只是用了一下這個地址作為判斷條件。
3.2 指針減指針
當同類型的地址減去同類型的另外一個地址,得出的結果的絕對值是兩個地址之間的元素個數。
需要注意的是,兩個指針指向的必須是同一塊內存,不然毫無意義。
????????那么有同學會想,指針+指針得到的結果是什么呢,這個結果毫無意義,類似于你可以把日期相減,得到天數,但是你不能把日期相加,這樣就毫無意義。
3.3 指針的關系運算
其實就是地址之間的比較,判斷兩個地址誰大誰小,從而對地址指向的內容進行操作。
4. 二級指針
? ? ? ? 簡單描述一下,就是指針變量里面存的地址,這個地址是一個指針的地址。乍一聽是不是以為在說繞口令呢?下面用一張圖來進行詮釋。
????????上圖中表示int * pa = &a;我們可以這么理解:*號表明pa的類型是一個指針類型,int表明這個指針類型指向的是int類型;那么我們是不是可以來理解一下二級指針。
? ? ? ? int* *ppa = &pa;還是將類型拆開,距離ppa最近的*表明ppa是一個指針,int* 表明ppa指向的類型是int*的類型。
總結:二級指針是用來存放一級指針變量的地址。
5. 指針數組
主語是數組,即存放指針的數組就是指針數組。
5.1 如何使用指針數組模擬二維數組
????????首先構造出三個一維數組,所謂二維數組就是將這三個一維數組連起來;我們構造一個指針數組,分別存入之前構造的一維數組名,在之前的帖子說明,一維數組名是數組的第一個元素的地址,所以分別存入了三個地址,我們需要遍歷指針數組,得到三個一維數組的首地址,再引入一個變量j,根據指針加減法,就可以訪問一維數組中除了第一個元素的其他元素的地址,最后解引用就可以得到最后的結果。
#include <stdlib.h>int main()
{int arr1[4] = {1,2,3,4};int arr2[4] = {2,4,6,8};int arr3[4] = {3,6,9,12};
// 用一維數組模擬出二維數組的效果int* arr_sum[3] = {arr1,arr2,arr3};for(int i = 0;i < 3;i++){for(int j = 0;j < 4;j++){printf("%d ",*(arr_sum[i] + j));}printf("\n");}return(0);
}