通常來說,指針是一個其數值爲地址的變量(或更通常地說是一個數據對象)。
正如char類型的變量用字符做爲其數值,而int類型變量的數值是整數,指針變量的數值表示的是地址。
若是您將某個指針變量命名爲ptr,就可使用以下語句:
ptr=&pooh; /*把pooh的地址賦給ptr*/
對於這個語句,咱們稱ptr指向pooh。ptr和&pooh的區別在於前者爲一變量,然後者是一個常量。固然,ptr能夠指向任何地方:
ptr=%bah; /*令ptr指向bah而不是pooh*/
這時,ptr的值是bah的地址。
要建立一個指針變量,首先須要聲明其類型。假設您想把ptr聲明爲能夠存放一個int數值的地址,就須要 使用下面介紹的新運算符。編程
9.7.1 間接運算符
假定ptr指向bah,以下所示:
ptr = &bah;
這時就能夠使用間接(indirection)運算符*(也稱做取值(dereferencing))來獲取bah中存放的數值(不要把這種一元運算符和表示乘法的二元運算符*相混淆)。
val = *ptr; /*獲得ptr指向的值*/
語句ptr=&bah;以及語句val=*ptr;放在一塊兒等同於下面的語句:
val = bah;
由此看出,使用地址運算符和間接運算符能夠間接完成上述語句的功能,這也正是「間接運算符」名稱的由來。編程語言
9.7.2 指針聲明
pointer ptr; /*不能這樣聲明一個指針*/
爲何不能這樣聲明?由於這對於聲明一個變量爲指針是不夠的,還須要說明指針所指向變量的類型。緣由是不一樣的變量類型佔用的存儲空間大小不一樣,而有些指針操做須要知道變量類型所佔用的存儲空間。同時,程序也須要了解地址中存儲的是何種類型的數據。例如,long和float兩種類型的數值可能使用相同大小的存儲空間,可是它們的數據存儲方式徹底不一樣。指針的聲明形式以下:
int *pi; /*pi是指向一個整數變量的指針*/
char *pc; /*pc是指向一個字符變量的指針*/
float *pf,*pg; /*pf和pg是指向浮點變量的指針*/
類型標識符代表了被指向變量的類型,而星號(*)表示該變量爲一指針。聲明int *pi; 的意思是pi是一個指針,並且*pi是int類型的。
*和指針之間的空格是可選的。
pc所指向的值(*pc)是char類型的。而pc自己又是什麼類型呢?咱們把它描述爲「指向char的指針」類型。pc的值是一個地址,在大多數系統內部,它由一個無符號整數表示。可是,這並不表示能夠把指針看做是整數類型。一些處理整數的方法不能用來處理指針,反之亦然。例如,能夠進行兩個整數相乘,而指針則不能。所以,指針的確是一種新的數據類型,而不是整數類型。因此,正如前面提到的,ANSI C 專門爲指針提供了%p輸出格式 。函數
9.7.3 使用指針在函數間通訊spa
在程序清單9.15中,函數interchange()使用了指針參數,咱們將對該函數進行詳細的討論。指針
程序清單9.15 swap3.c程序code
#include <stdio.h> void interchange(int *u,int *v); int main(void) { int x = 5,y = 10; printf("Originally x = %d and y=%d.\n",x,y); interchange(&x,&y); /*向函數傳送地址*/ printf("Now x = %d and y = %d.\n",x,y); return 0; } void interchange(int *u,int *v) { int temp; temp = *u; /*temp獲得u指向的值*/ *u = *v; *v = temp; }
下面咱們分析程序清單9.15的運行狀況,首先,函數調用語句以下:對象
interchange(&x,&y);ci
能夠看出,函數傳遞的是x和y的地址而不是它們的值。這就意味着interchange()函數原型聲明和定義中的形式參數u和v將使用地址做爲它們的值。所以,它們應該聲明爲指針。因爲x和y都是整數,因此u和v是指向整數的指針。其聲明以下:原型
void interchange(int *u,int *v)io
接下來,函數體進行以下聲明:
int temp;
從而提供了所需的臨時變量。爲了把x的值存儲在temp中,須要使用如下語句:
temp = *u;
注意,由於u的值是&x,因此u指向x的地址。這就意味着*u表明了x的值,而這正是咱們須要的數值。不要寫成以下這樣:
temp = u; /*這樣作不行*/
上面的語句中,由於賦給變量temp的只是x的地址而不是x的值,因此不能實現數值的交換。
一樣,把y的值賦給x,須要使用下面的語句:
*u = *v;
其執行結果至關於:
x = y;
在示例程序中,咱們用一個函數實現了x和y的數值交換。首先,函數使用xy的地址做爲參數,這使它能夠訪問xy變量。經過使用指針和運算符*,函數能夠得到相應存儲地址的數據,從而就能夠改變這些數據。
一般狀況下,能夠把關於變量的兩類信息傳遞給一個函數。若是函數的調用形式以下:
funcation (x);
這是傳遞的是x的值。可是若是使用下面這種函數調用形式:
funcation (&x);
那麼會把x的地址傳遞給函數。第一種調用形式要求函數定義部分必須包含一個和x具備相同數據類型的形式參數。以下所示:
int function (int num);
而第二種形式要求函數定義部分的形式參數必須是指向相應數據類型的指針:
int funcation (int *ptr);
使用函數進行數據計算等操做時,可使用第一種形式。可是,若是須要改變調用函數中的多個變量的值時,就須要使用第二種形式。其實,使用scanf()時已經使用了第二種形式。例如,當須要爲變量num讀取一個數值時,能夠調用函數scanf("%d",&num);該函數調用的意思是先讀取一個數值,而後將其存儲到經過參數得到的地址中。
儘管interchange()只使用局部變量,可是經過使用指針,該 函數能夠操做main()中變量的值。
***************************************************
關於變量:變量名稱、地址和數值
前面關於指針的討論中,變量名稱、地址以及數值之間的關係是其關鍵所在。
編寫程序時,一個變量通常有兩種屬性:變量名和數值(固然,還有其餘屬性,如數據類型等,但它們與這個主題無關)。程序被編譯和加載後,同一個變量在計算機中的兩個屬性是地址和數值。變量的地址能夠被看做是在計算機中變量的名稱。
在許多編程語言中,變量地址只由計算機處理,對於編程人員來說徹底不可見。可是在C中,可使用運算符&對變量的地址進行操做。
&barn就表示變量barn的地址。
能夠經過使用變量名得到變量的數值。
例如printf("%d\n",barn)輸出的是barn的數值。
固然 ,也可使用運算符*從地址中獲取相應的數值。
對於語句pbarn = &barn;,*pbarn是存儲在地址&barn中的數值。
總之,普通的變量把它的數值做爲基本數值量,而經過使用運算符&將它的地址做爲間接數值量。可是對於指針 來說,地址是它的基本數值量,使用運算符*後,該地址中存儲的數值是它的間接數值量。