二.指標的定義及運算1.指標的定義
在c語言中,定義乙個普通的變數(如整型數),我們這樣做:int i; 而定義乙個指標變數(指標)我們需要這樣做:int *p ; 還記得嗎,乙個矩形中的值是有型別的,可能是整型,可能是字元型……,它們原本是「清白」的,無型別的,是我們通過一些手段使它們有了型別。當我們做出int i; 這樣乙個定義時,編譯器就會分配乙個位址(例如200)並和i 關聯起來,而int將限定編譯器把這個區域中的內容作為整型數看待。
現在我們又有了int *p;這個定義,假設p是指向變數i的(見下圖),p中存的是變數i的位址。* 表示p是乙個指標,而int表示p中所存的位址對應的變數(即變數i)的型別是int。
我們將int稱為指標p的基型別,或指標p所指向的變數的型別。
類似地,我們可以有: char *s ; ( s是指向char型變數的指標 )
float *f ; ( f是指向float型變數的指標 )
double *d ; ( d是指向double型變數的指標 )
由此得到宣告乙個指標變數(指標)的一般形式 : 基型別 * 指標名;
有一點要注意,在定義指標時,以下兩種方式都是允許的,例如:
int *ptr1;
int* ptr2;
但一般比較傾向用第一種,因為可以避免以下的誤解:
int* prt1, ptr2;
這樣的定義方式,容易使人誤以為ptr2也是乙個指標,事實上並不是,prt2是乙個int型變數,以下的定義方式中ptr1與ptr2才都是指標:
int* ptr1, *ptr2;
2.指標的運算
究竟如何使乙個指標指向乙個變數呢?後面的語句給出了解答:int *p = &i;& 用於取乙個物件的位址(本文說的物件是泛指的某一事物,如變數,陣列等,和
c++中的物件概念不同)
小擴充套件:(下面大括號中的內容,出涉指標的朋友可以跳過,當然也可以作為擴充套件知識)
<2>.* (dereference operator) 解引用操作符
* 在定義時用來說明乙個變數是指標,而在定義了乙個指標之後,我們使用(引用)指標時,*p表示的是p所指向的物件(即i)。也就是說,對於乙個已定義的指標使用 * 操作符,將訪問這個指標所指向的物件,我們來看下面的程式:
#include
int main()
int i; /*定義乙個int型變數i*/
int *p; /* 定義乙個指向int型別的指標p */
i = 2 ; /* 初始化i為2 */
p = &i ; /* 將i的位址賦給p ,即使p指向i */
printf("%d\n", i ) ; /*輸出i的值 */
printf("%d\n", *p ) ; /* 輸出p所指向的儲存單元的值,即i的值*/
return 0 ; /* 標準c語言主函式應返回乙個值,用以通知作業系統程式執行成功與否,通常0表示成功*/
程式輸出結果為:
對於 * 操作符,由於它有兩個等價的術語dereference和indirection ,所以在國內的書籍中你會看到各種翻譯方法,如:解引用、解除引用、反引用、反向引用、間接引用、間接訪問……
只要你知道它是用來訪問乙個指標所指向的物件的,那麼不管它叫什麼都不重要了。還是那句話,弄懂是什麼,不要在乎叫什麼,如果你理解了它的真正含義,大可以簡潔地稱它為「星號」操作符!
3.指標的初始化
ansi c定義了零指標常量的概念:乙個具有0值的整形常量表示式,或者此類表示式被強制轉換為void *型別,則稱為空指標常量,它可以用來初始化或賦給任何型別的指標。也就是說,我們可以將0、0l、'/0'、2–2、0*5以及(void*)0賦給乙個任何型別的指標,此後這個指標就成為乙個空指標,由系統保證空指標不指向任何物件或函式。
ansi c還定義了乙個巨集null,用來表示空指標常量。大多數c語言的實現中null是採用後面這種方式定義的:#define null ((void*)0)。
對指標進行初始化時常用的有以下幾種方式:
1.採用null或空指標常量,如:int *p = null;或 char *p = 2-2; 或float*p = 0;
3.將乙個指標常量賦給乙個指標,如:long *p = (long *)0xfffffff0;
4.將乙個t型別陣列的名字賦給乙個相同型別的指標,如:char ary[100]; char *cp = ary;
6.將乙個字串常量賦給乙個字元指標,如:char *cp = 「abcdefg」;
對指標進行初始化或賦值的實質是將一個位址或同型別
(或相相容的型別
)的指標賦給它,而不管這個位址是怎麼取得的。要注意的是:對於乙個不確定要指向何種型別的指標,在定義它之後最好把它初始化為
null
,並在解引用這個指標時對它進行檢驗,防止解引用空指標。另外,為程式中任何新建立的變數提供乙個合法的初始值是乙個好習慣,它可以幫你避免一些不必要的麻煩。
4.void *型指標
ansi c定義了一種void *型指標,表示定義乙個指標,但不指定它指向何種型別的資料。void *型指標作為一種通用的指標,可以和其它任何型別的指標(函式指標除外)相互轉化而不需要型別強制轉換,但不能對它進行解引用及下標操作。c語言中的malloc函式的返回值就是乙個void *型指標,我們可以把它直接賦給乙個其他型別的指標,但從安全的程式設計風格角度以及相容性上講,最好還是將返回的指標強制轉換為所需的型別,另外,malloc在無法滿足請求時會通過返回乙個空指標來作為「記憶體分配失敗」的訊號,所以要注意返回值指標的判空。
5.指向指標的指標
在指標初始化的第5種方式中提到了用乙個指標的位址來初始化乙個指標。回憶一下上一講的內容:指標是一種變數,它也有自己的位址,所以它本身也是可用指標指向的物件。我們可以將指標的位址存放在另乙個指標中,如:
int i = 5000;
int *pi = &i;
int **ppi =π
此時的ppi即是乙個指向指標的指標,下圖表示了這些物件:
i的位址為108,pi的內容就是i的位址,而pi的位址為104,ppi的內容即是pi的位址。對ppi解引用照常會得到ppi所指的物件,所獲得的物件是指向int型變數的指標pi。想要真正地訪問到i.,必須對ppi進行兩次解引用,如下面**所示:
printf("%d\n", i );
printf("%d\n", *pi );
printf("%d\n", **ppi );
以上三條語句的輸出均為5000。
二 指標的定義及運算
上一講已經說過,指標是一種變數,它也有自己的位址,但由於它是專門用來存放位址的變數,所以把它認為是種特殊的變數,既然有著特殊的身份,那麼也理應受到特殊的待遇,下面來看看它享受了那些優待。1 指標的定義 在c語言中,定義乙個普通的變數 如整型數 我們這樣做 int i 而定義乙個指標變數 指標 我們需...
指標學習二 指標 位址
通過位址的呼叫來改變變數的值 includevoid f int p void g int k int main void f int p void g int k i 0063fe9c p 0063fe9c p 6 k 26定義乙個變數p,它位於2000單元,該單元存放了變數x的位址1000。此時...
C語言 二 指標
一 指標概述 1.簡介 2.初始化 1 先定義後初始化 int a 10 int p p a 2 定義並初始化 int a 10 int p a 備註 在資料型別後,變數名稱前的 是乙個說明符,用來說明該變數是乙個指標變數。如果前面沒有資料型別,如 p,這裡的 是乙個指標運算子,用來取出指標變數所指...