天天看點

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

1. 回想一下,之前我們是如何更改某個變量的值?

我們之前是通過變量名來直接引用變量,然後進行指派:

2. 看上去是很簡單,其實程式内部是怎麼操作的呢?

其實,程式對變量的讀寫操作,實際上是對變量所在的存儲空間進行寫入或取出資料。就上面的代碼而言,系統會自動将變量名a轉換為變量的存儲位址,根據位址找到變量a的存儲空間,然後再将資料10以2進制的形式放入變量a的存儲空間中。

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

3. 通過變量名引用變量,由系統自動完成變量名和其存儲位址之間的轉換,稱為變量的"直接引用"方式

1.我們已經知道,"直接引用"是直接通過變量名來讀寫變量

2.c語言中還有一種"間接引用"的方式(以變量a為例):首先将變量a的位址存放在另一個變量中,比如存放在變量b中,然後通過變量b來間接引用變量a,間接讀寫變量a的值。這就是"間接引用"。

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

如果程式通過"間接引用"的方式來修改a的值,可以這樣做:先根據 變量名b 擷取 變量b 的位址ffc2,取出變量b中存儲的内容ffc1,也就是變量a的位址,再根據變量a的位址ffc1找到a的存儲空間,然後修改裡面的資料。

3.總結一句:用來存放變量位址的變量,就稱為"指針變量"。在上面的情況下,變量b就是個"指針變量",我們可以說指針變量b指向變量a。

一般形式:類名辨別符  *指針變量名;

"*"是一個說明符,用來說明這個變量是個指針變量,是不能省略的,但它不屬于變量名的一部分

前面的類型辨別符表示指針變量所指向的變量的類型,而且隻能指向這種類型的變量

注意第8行,指派給p的是變量a的位址&a

指針變量是用來存放變量位址的,不要給它随意指派一個常數。下面的寫法是錯誤的

當程式剛執行完第5行代碼時,記憶體中大概的分布情況是這樣的

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

,a值是10,p值就是變量a的位址ffc3。

注意下第5、第8行,都有個"*",它們的含義是不一樣的:

(1) 第5行的"*"隻是用來說明p是個指針變量

(2) 第8行的"*"是一個指針運算符,這裡的*p代表根據p值ffc3這個位址通路對應的存儲空間,也就是變量a的存儲空間,然後将右邊的數值9寫入到這個存儲空間,相當于 a = 9;,于是記憶體中就變成這樣了

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

輸出結果為:

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

,可以發現,我們通過變量p間接修改了變量a的值。

指針運算符除了可以指派之外,還可以用于取值

輸出結果:

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

,第6行中的*p的意思是:根據p值(即變量a的位址)通路對應的存儲空間,并取出存儲的内容(即取出變量a的值),指派給value

在指針變量沒有指向确定位址之前,不要對它所指的内容指派。下面的寫法是錯誤的

應該在指針變量指向一個确定的變量後再進行指派。下面的寫法才是正确的

前面我們通過指針變量p間接通路了變量a,在有些人看來,覺得指針變量好傻b,直接用變量名a通路變量a不就好了麼,幹嘛搞這麼麻煩。别着急,接下來舉個例子,讓大家看看指針還能做什麼事情。

現在有個要求:寫一個函數swap,接收2個整型參數,功能是互換兩個實參的值。

1> 如果沒學過指針,你可能會這樣寫

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

,雖然v1和v2的值被交換了,但是變量a和b的值根本就沒有換過來。因為基本資料類型作為函數實參時,隻是純粹地将值傳遞給形參,形參的改變并不影響實參。

我們可以簡要分析一下這個過程:

* 在第20行中,将變量a、b的值分别傳遞給了swap函數的兩個形參v1、v2

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

* 在第8行中,将v1的值指派給了temp

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

* 在第9行中,将v2的值指派給了v1

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

* 在第10行中,将temp的值指派給了v2

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

就這樣,v1和v2的值被交換了,但是a和b的值一直都沒有改變

2> 如果學了指針,就應該這樣寫

先看看輸出結果:

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

,變量a和b的值終于換過來了。

解釋一下:

(在16位編譯器環境下,一個指針變量占用2個位元組)

* 先注意第20行,傳遞是變量的位址。是以swap函數的形參v1指向了變量a,v2指向了變量b

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

* 第6行代碼是取出v1指向的變量的值,也就是變量a的值:10,然後指派給變量temp

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

* 第9行代碼是取出v2指向的變量(變量b)的值,然後指派給v1指向的變量(變量a)

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

* 第12行代碼是将temp變量的值指派給v2指向的變量(變量b)

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

相信你已經感受到指針的強大了,如果沒有指針,在一個函數的内部根本改變不了外部的實參。

接下來再舉一個指針的實用例子。預設情況下,一個函數隻能有一個傳回值,有了指針,我們可以實作函數有"多傳回值"。

現在有個要求:寫一個函數sumandminus,可以同時計算2個整型的和與差,函數執行完畢後,傳回和與差(注意了,這裡要傳回2個值)

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

,和與差都由同一個函數計算并傳回出來。和是函數的直接傳回值,差是通過函數的第3個指針參數間接傳回。

是以有了指針,我們可以讓函數有"無限個"傳回值。

剛學完指針,都可能有一大堆的疑惑,這裡我列出幾個常見的疑惑吧。

在同一種編譯器環境下,一個指針變量所占用的記憶體空間是固定的。比如,在16位編譯器環境下,任何一個指針變量都隻占用2個位元組,并不會随所指向變量的類型而改變。

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

其實,我覺得這個問題跟"數組為什麼要分類型"是一樣的。

* 看下面的代碼,利用指針p讀取變量c的值

這個輸出結果應該難不倒大家:

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

,是可以成功讀取的。

* 如果我改一下第5行的代碼,用一個本應該指向int類型變量的指針p,指向char類型的變量c

我們再來看一下輸出:

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

,c的原值是1,現在取出來卻是513,怎麼回事呢?這個要根據記憶體來分析

根據變量的定義順序,這些變量在記憶體中大緻如下圖排布:

其中,指針變量p和int類型變量i各占2個位元組,char類型的c占一個位元組,p指向c,是以p值就是c的位址

指針[收藏]一、什麼是指針?二、指針的定義三、指針的初始化四、指針運算符五、指針的用途舉例六、關于指針的疑問

1> 最初的時候,我們用char *p指向變量c。當利用*p來擷取變量c的值時,由于指針p知道變量c是char類型的,是以會從ffc3這個位址開始讀取1個位元組的資料:0000 0001,轉為10進制就是1

2> 後來,我們用int *p指向變量c。當利用*p擷取變量c的值時,由于指針p認為變量c是int類型的,是以會從ffc3這個位址開始讀取2個位元組的資料:0000 0010 0000 0001,轉為10進制就是513

可見,給指針分類是多麼重要的一件事,而且一種指針最好隻指向一種類型的變量,那是最安全的。

上一篇: Python中time
下一篇: Python中的