C語言之指標

2021-04-06 20:44:00 字數 4690 閱讀 4189

指標型別的本質分析

1、指標的本質

指標的本質:一種復合的資料型別。下面我將以下面幾個作為例子進行展開分析:

a)、int *p;

b)、int **p;

c)、int (*parvalue)[3];

d)、int (*pfun)();

分析:所謂的資料型別就是具有某種資料特徵的東東,比如資料型別char,它的資料特徵就是它所佔據的記憶體為1個位元組, 指標也很類似,指標所指向的值也佔據著記憶體中的一塊位址,位址的長度與指標的型別有關,比如對於char型指標,這個指標佔據的記憶體就是1個位元組,因此指 針也是一種資料型別,但我們知道指標本身也佔據了乙個記憶體空間位址,位址的長度和機器的字長有關,比如在32位機器中,這個長度就是4個位元組,因此指標本 身也同樣是一種資料型別,因此,我們說,指標其實是一種復合的資料型別,

好了,現在我們可以分析上面的幾個例子了。

假設有如下定義:

int nvalue;

那麼,nvalue的型別就是int,也就是把nvalue這個具體變數去掉後剩餘的部分,因此,上面的4個宣告可以模擬進行分析:

a)、int *

*代表變數(指標本身)的值是乙個位址,int代表這個位址裡面存放的是乙個整數,這兩個結合起來,int *定義了乙個指向整數的指標,類推如下:

b)、int **

指向乙個指向整數的指標的指標。

c)、int (*)[3]

指向乙個擁有三個整數的陣列的指標。

d)、int (*)()

指向乙個函式的指標,這個函式引數為空,返回值為整數。

分析結束,從上面可以看出,指標包括兩個方面,乙個是它本身的值,是乙個記憶體中的位址;另乙個是指標所指向的物,是這個位址中所存放著具有各種各樣意義的資料。

2、對指標本身值的分析

下面例子考察指標本身的值(環境為32位的計算機):

void *p = malloc( 100 );

請計算sizeof ( p ) = ?

char str = 「hello」 ;

char *p = str ;

請計算sizeof ( p ) = ?

void func ( char str[100])

分析:上面的例子,答案都是4,因為從上面的討論可以知道,指標本身的值對應著記憶體中的乙個位址,它的size只與機器的字長有關(即它是由系統的記憶體模型決定的),在32位機器中,這個長度是4個位元組。

3、對指標所指向物的分析

現在再對指標這個復合型別的第二部分,指標所指向物的意義進行分析。

上面我們已經得到了指標本身的型別,那麼將指標本身的型別去掉 「*」號就可得到指標所指向物的型別,分別如下:

a)、int

所指向物是乙個整數。

b)、int*

所指向物是乙個指向整數的指標。

c)、int ()[3]

()為空,可以去掉,變為int [3],所指向物是乙個擁有三個整數的陣列。

d)、int ()()

第乙個()為空,可以去掉,變為int (),所指向物是乙個函式,這個函式的引數為空,返回值為整數。

4、附加分析

另外,關於指標本身大小的問題,在c++中與c有所不同,這裡我也順帶談一下。

在c++中,對於指向物件成員的指標,它的大小不一定是4個位元組,這主要是因為在引入多重虛擬繼承以及虛函式的時候,有些附加的資訊也需要通過這個指 針進行傳遞,因此指向物件成員的指標會增大,不論是指向成員資料,還是成員函式都是如此,具體與編譯器的實現有關,你可以編寫個很小的c++程式去驗證一 下。另外,對乙個類的靜態成員(static member,可以是靜態成員變數或者靜態成員函式)來說,指向它的指標只是普通的函式指標,而不是乙個指向類成員的指標,所以它的大小不會增加,仍舊是 4個位元組。

指標運算子&和*

「&和*」,它們是一對相反的操作,』&』取得乙個物的位址(也就是指標本身),』*』得到乙個位址裡放的物(指標所指向的物)。這個東西可以是值(物件)、函式、陣列、類成員(class member)等等。

參照上面的分析我們可以很好地理解&與*。

使用指標的好處?

關於指標的本質和基本的運算子我們討論過了,在這裡,我想再籠總地談一談使用指標的必要性和好處,為我們今後的使用和對後面篇章的理解做好鋪墊。簡而言之,指標有以下好處:

1)、方便使用動態分配的陣列。

這個解釋我放在本系列第六篇中進行講解。

2)、對於相同型別(甚至是相似型別)的多個變數進行通用訪問。

就是用乙個指標變數不斷在多個變數之間指來指去,從而使得非常應用起來非常靈活,不過,這招也比較危險,需要小心使用:因為出現錯誤的指標是程式設計中非常忌諱的事情。

3)、變相改變乙個函式的值傳遞特性。

說白了,就是指標的傳位址作用,將乙個變數的位址作為引數傳給函式,這樣函式就可以修改那個變數了。

4)、節省函式呼叫代價。

我們可以將引數,尤其是大個的引數(例如結構,物件等),將他們位址作為引數傳給函式,這樣可以省去編譯器為它們製作副本所帶來的空間和時間上的開銷。

5)、動態擴充套件資料結構。

因為指標可以動態地使用malloc/new生成堆上的記憶體,所以在需要動態擴充套件資料結構的時候,非常有用;比如對於樹、鍊錶、hash表等,這幾乎是必不可少的特性。

6)、與目前計算機的記憶體模型相對應,可按照記憶體位址進行直接訪問,這使得c非常適合於一些較底層的應用。

這也是c/c++指標乙個強大的優點,我會在後面講述c語言的底層操作時,較詳細地介紹這個優點的應用。

7)、遍歷陣列。

據個例子來說吧,當你需要對字串陣列進行操作時,想一想,你當然要用字串指標在字串上掃來掃去。

…實在太多了,你可以慢慢來補充^_^。

指標本身的相關問題

1、問題:空指標的定義

曾經看過有的.h檔案將null定義為0l,為什麼?

答案與分析:

這是乙個關於空指標巨集定義的問題。指標在c語言中是經常使用的,有時需要將乙個指標置為空指標,例如在指標變數初始化的時候。

c語言中的空指標和pascal或者lisp語言中的nil具有相同的地位。那如何定義空指標呢?下面的語句是正確的:

char *p1 = 0;

int *p2;

if (p != 0)

p2 = 0;

也就是說,在指標變數的初始化、賦值、比較操作中,0會被編譯器理解為要將指標置為空指標。至於空指標的內部表示是否是0,則隨不同的機器型別而定,不 過通常都是0。但是在另外一些場合下,例如函式的引數原型是指標型別,函式呼叫時如果將0作為引數傳入,編譯器則不能將其理解為空指標。此時需要明確的類 型轉換,例如:

void func (char *p);

func ((char *)0);

一般情況 下,0是可以放在**中和指標關聯使用的,但是有些程式設計師(數量還不少呦!也許就包括你在內)不喜歡0的直白,認為其不能表示作為指標的特殊含義,於是要 定義乙個巨集null,來明確表示空指標常量。這也是對的,人家c語言標準就明確說:「 null應該被定義為與實現相關的空指標常量」。但是將null定義成什麼樣的值呢?我想你一定見過好幾種定義null的方法:

#define null 0

#define null (char *)0

#define null (void *)0

在我們使用的絕大多數計算系統上,例如pc,上述定義是能夠工作的。然而,世界上還有很多其它種類的計算機,其cpu也不是intel的。在某些系統 上,指標和整數的大小和內部表示並不一致,甚至不同型別的指標的大小都不一致。為了避免這種可移植性問題,0l是一種最為安全的、最妥帖的定義方式。0l 的含義是: 「值為0的整數常量表示式」。這與c語言給出的空指標定義完全一致。因此,建議採用0l作為空指標常量null的值。

其 實 null定義值,和作業系統的的平台有關, 將乙個指標定義為 null, 其用意是為了保護作業系統,因為通過指標可以訪問任何一塊位址, 但是,有些資料是不許一般使用者訪問的,比如作業系統的核心資料。 當我們通過乙個空(null)的指標去方位資料時,系統會提示非法, 那麼系統又是如何知道的呢??

以windows2000系統為例, 該系統規定系統中每個程序的起始位址(0x00000000)開始的某個位址範圍內是存放系統資料的,使用者程序無法訪問, 所以當使用者用空指標(0)訪問時,其實訪問的就是0x00000000位址的系統資料,由於該位址資料是受系統保護的,所以系統會提示錯誤(指標訪問非 法)。

這也就是說null值不一定要定義成0,起始只要定義在系統的保護範圍的位址空間內,比如定義成(0x00000001, 0x00000002)都會起到相同的作用,但是為了考慮到移植性,普遍定義為0 。

指標既然這麼重要,而且容易出錯,那麼有沒有方法可以很好地減少這些指標相關問題的出現呢?

答案與分析:

減少出錯的根本是徹底理解指標。

1) 未使用的指標初始化為null 。

2) 在給指標分配空間前、分配後均應作判斷。

3) 指標所指向的內容刪除後也要清除指標本身。

要牢記指標是乙個復合的資料結構這個本質,所以我們不論初始化和清除都要同時兼顧指標本身(上述規則1,3)和指標所指向的內容(上述規則2,3)這兩個方面。

遵循這些規則可以有效地減少指標出錯,我們來看下面的例子:

void test(void)

} 請問執行test函式會有什麼樣的結果?

答:篡改動態記憶體區的內容,後果難以預料,非常危險。因為free(str);之後,str成為野指標,if(str != null)語句不起作用。

如果我們牢記規則3,在free(str)後增加語句:

str = null;

那麼,就可以防止這樣的錯誤發生。

C語言之指標

指標的概念 什麼是指標?如果用一句話概括的的話那就是,乙個存放記憶體空間位址的變數。指標也是乙個變數,指標存放的內容是乙個位址,該位址指向乙個記憶體空間。指標變數的定義 int p 該變數用來存放乙個空間的位址。p 代表該指標指所指向記憶體空間中的值,切記指標只能存放有效的記憶體空間位址,不能存放其...

C語言之指標

指標是c語言學習乙個重要的概念,它極大的方便了c語言程式設計,用好了指標可以幫助我們程式設計,但是同時指標也是飽受爭議,因為指標的使用很容易出錯,所以在一開始學的時候就弄懂有關指標的知識點是必要的。那麼指標是什麼呢?其實指標也是一種變數,和其他型別的變數一樣,也是儲存資料的,只是在指標變數裡面儲存的...

C語言之指標

記憶體單元的編號也叫做位址。既然根據記憶體單元的編號或者位址就可以找到所需的記憶體單元,所以通常把這個位址稱為指標。在c語言中,允許用乙個變數來存放指標,這種變數稱為指標變數,因此,乙個指標變數的值就是某個記憶體單元的位址或稱為某記憶體單元的指標。型別說明符 變數名 例 int p2 float p...