天天看點

C/C++ 學習筆記四(指針、數組)

什麼是指針?

指針其實是記憶體單元位址

什麼是指針變量?

指針變量是用于存儲記憶體單元位址的變量

指針變量存儲的實質

顧名思義,指針變量存儲的是記憶體單元的值,即存儲的值其實指向的一個特定類型記憶體區域的起始位址。

如下例子,整型變量a的值為123,其記憶體單元位址為0x104,指針變量存儲的值是變量a的記憶體單元0x104。

指針變量指向了記憶體位址起始為0x104,長度為4個位元組的記憶體單元。p也可以對這個4個單元進行操作。

C/C++ 學習筆記四(指針、數組)

c語言中,我們可以像普通整型資料一樣,對指針變量進行運算。

指針變量的轉換

普通類型的指針變量都可以直接指派void *空類型指針,

但空類型指針需要強轉才可以轉成普通類型指針。

void 指針是一種特殊的指針,表示“無類型的指針”,因為其沒有指定類型,所有它可以指向任何類型的資料,也就是說任何類型的指針可以直接複制給void指針。

但是void指針指派給其他類型的指針時,必須強制轉換

這是因為指定了類型的指針變量指向了記憶體的一塊區域,但空類型指針無法确定指向記憶體區域的大小。

需要注意的是,不同類型指針變量互相轉換時,需避免通路非法的記憶體區域,導緻程式異常退出。

如下例子,chP指向了一段長度為1位元組的變量a的記憶體區域,當其強制轉換成int指針時,則超出了編譯器配置設定的記憶體區域,程式會異常退出。

指針變量的算術運算

指針變量可以使用算術運算符實作自增減,如下例

假設&a位址為0x100,則上面例子的輸出為

即使指針變量的算術運算為增減sizeof(資料類型)的大小。上例子中p的值為0x100,強轉為char 後自增1,結果為0x101,強轉為double 後自增1為,0x108(0x100+0x8)。

C/C++ 學習筆記四(指針、數組)

同理因為空指針類型無法得知其指向區域的長度,void *指針便無法進行增減操作。

C語言中,數組與指針是一種非常暧昧的關系,因數組和指針經常可以互相的轉換,是以經常會将其兩者混淆。

真正的事實是,兩者擁有不同的存儲結構,但引指針的靈活性,兩者可以互相的引用、轉換。

數組的存儲結構

與指針的存儲結構相比,數組在記憶體中占據的是連續的位元組單元。即指針存儲的長度根據計算機不同,是一個固定的大小 (32位4個位元組、64位8個位元組),數組存儲的是一塊連續的記憶體區域。

C/C++ 學習筆記四(指針、數組)

那為什麼指針可以通路數組中元素?

這是因為數組辨別符表示的是該數組的第一個元素的位址,當指針指向數組辨別符時,便可以通過指針通路數組中的各個元素。

函數調用時數組作為參數時為位址傳遞

C語言的标準中規定:所有的數組在作為參數傳遞時,都轉換成指向數組起始位址的指針,其他參數均采用值傳遞。

采用位址傳遞好處是形參不存在存儲空間,編譯系統不為形參配置設定記憶體,數組名或者指針便是一組連續空間的首位址。

例如下面例子輸出的size都為4。

數組和指針其實并不是一個相同概念,雖然在日常的使用中,經常可以使用指針代替數組,用于周遊數組的元素,例如

再來一個例子,可以證明數組并不是指針:

執行上面代碼會提示“a”: 重定義;不同的間接尋址類型

在使用extern int a時,編譯器認為a是一個在外部聲明的整型指針變量,但f1.c中,a是一個長度為3的整型數組,在32位系統系統下,int 長度為4位元組,而int [3]長度為4*3 = 12位元組。

再看一個例子

程式執行後列印different。這是因為a指向的是存儲于資料段靜态變量hello,arr則指向編譯器配置設定的記憶體空間。兩者的值并不一樣。

對于數組而言,編譯器已經為數組配置設定了一定的空間以及對應的位址,通過數組位址的偏移,可以通路該數組的元素。

而指針,編譯器為其配置設定了空間,用于存儲位址值。而對于存放在其中的值,隻有在程式運作時才能知道。

1. 使用指針前必須初始化,否則會指向錯誤的記憶體區域,導緻程式異常。

2.使用NULL指針作為函數調用失敗的傳回值。類似malloc函數,當配置設定記憶體失敗時傳回NULL,用以表示為一種異常情況。

3.在不知記憶體區域具體類型情況下,避免對void 指針進行算術操作

例如,下例子對p任何的操作都會導緻程式出錯

4. 不同類型指針轉換時,注意不超出編譯器配置設定的記憶體區域。

如下例子,ip使用了超出了編譯器配置設定的記憶體,會導緻程式異常退出

5.避免指針和整型資料的直接轉換。

1.指針變量是變量,存儲記憶體位址的變量。

3.數組存儲的是一段連續的記憶體區域

4.數組辨別符存儲了,一段記憶體區域的起始位址

5.數組作為參數傳遞時是位址傳遞,其他類型則為值傳遞