# 指標的概念
指標是一種數據類型,指標與內存單元的地址密切相關。
# 內存單元
內存:由內存單元構成
# 內存單元的地址與內容
內存單元的地址:指內存單元的編號
內存單元的內容:存放在內存單元中的數據
# 內存單元的直接與間接訪問
在 C/C++ 語言中,每個變數都分配有確定的內存空間。
使用變數名可直接訪問內存中的數據;
通過變數的地址也可間接訪問內存中的數據。
# 地址與指標
定義一個變數,系統按變數類型為變數分配不同數目的內存單元,將其第一個內存單元的地址作為變數的地址。如: int a;
在 C/C++ 中,允許定義一種特殊變數,用於存放某變數的地址。
現假設變數 pta
中存放著整數變數 a
的地址。 pta=&a;
pta 與變數 a 之間的關聯,形像地表示為: pta->a
讀作: pta
指向 a
。
其中: ->
為指標示意符。
由此,我們說 pta
中存放的是指向變數 a
的指標。即 pta
是一個指標變數。
將存放 “地址” 的變數稱為指標變數,這裡的 “地址” 就是指標。
因此,變數的地址就是變數的指標。
# 指標類型的主要用途
- 參數傳遞
指標作參數可以實現參數按引用傳遞的功能。 - 動態分配
利用動態分配可構建動態數組,動態數組需要藉助指標實現。 - 數據結構
創建可伸縮的數據結構,如鍊表、棧與隊列、樹和圖等。 - 多態處理
面向對象編程中 “運行多態性” 的處理是利用指標與引用實現的。
# 指標變數的使用
變數有地址,指標變數可以存放變數的地址。
當指針變數中存放某個變數的地址後,我們就說該指標變數指向這個變數。
# 定義指標變數
即給指標變數分配內存空間
<資料型態> *<變數名>; |
*
是指標類型變數的標誌符號。<變數名>
為指標變數名(構成同標識符)。<資料型態>
為指標變數所指向變數的資料型態。<資料型態> *
表示指標類型。
# 初始化
- 在定義指標變數的同時為指標變數提供初值。
如:int a=5,*pta=&a;
其中a
的初值為5
,pta
的初值為整型變數a
的地址
即,指標變數pta
指向變數a
,pta->a
。 - 使用賦值語句為變量提供初始值
上述定義語句:int a=5,*pta=&a;
與下面語句組的功能是等效的。
int a, *pta; // 先定義變數 | |
a = 5; // 使用賦值語句提供初值 | |
pta = &a; // 使用賦值語句提供初值 |
pta=&a;
不可寫成: *pta=&a;
因為, *pta
並不表示指標變數 pta
,而表示 pta
所指向的變數 a
。 指針變數與指標變數所指向的變數是兩個完全不同的概念。
# 單元運算子 &
*
&
取地址運算子
&<變數名> // 獲得該變數內存單元位址 |
*
指標運算子
也稱為間接訪問運算子
// 表示該指標所指向的變數 | |
*<指標變數名> | |
// 或 | |
*<指標常數> |
如果指標變數 pta
中存放著變數 a
的指標,則 *pta
表示 pta
所指向的變數即變數 a
。這是一種間接訪問的表示。
int a=5,*pta=&a; | |
*pta=a+8; | |
cout<<a<<","<<*pta<<endl; | |
// 在這裡,*pta 是表示 pta 所指的對象,即變數 a。 | |
// *pta 等同於變數 a | |
// 輸出結果為:13,13 |
int a=5,*p=&a; | |
cout<<&a<<endl;//a 的地址 0x23fe4c | |
cout<<a<<endl;//a 的值 5 | |
cout<<&p<<endl;//p 的地址 0x23fe40 | |
cout<<p<<endl;//p 的值 0x23fe4c | |
cout<<*p<<endl;//p 所指變數的值 5 |
*p
與*(&a)
等價,即就是a
。p
是一個指標變數,而&a
是一個指標常數。- 指標變數的值一定是 “地址”;指標變數所指對象的值不一定是 “地址”。
# 注意
- 不要訪問沒有被初始化的指標變數
int *p; | |
cin>>*p; |
由於 p
變數為初始化, p
中可能存放一個不確定的單元地址,這時的輸入將會改變原存儲單元的值,造成結果混亂。
- 指標變數可以有空值,即指標不指向任何變數
常用符號常數NULL
表示空指標,其實,NULL
表示的值其實是整數0
。變異系統約定0
單元不放存有效數據。
# 函式與指標
一個函式在編譯時被分配一個入口地址,這個入口地址就稱為函式的指標。
在 C++ 中, 函式名代表函式的入口地址。
# 指標作函數的參數
實現地址傳遞,用途如下:
- 指標作函式參數,這時形參接受的是實參的地址。函式中通過對指針的間接訪問實現參數的按 “引用傳遞” 功能。
- 設置多個指標參數可從函式中帶回多個結果值。
- 對於傳遞一塊連續的內存區域數據,傳遞首地址比傳遞數據值,不僅開銷小而且效率高。
# 例子:地址傳遞
編寫交換兩個變數值的函式
// 實現交換的函數 | |
void swap(int *xp, int *yp) // 形參為指標變數 | |
{ | |
int t; | |
t = *xp; | |
*xp = *yp; // 交換時透過間接訪問運算子 | |
*yp = t; | |
} | |
// 主函式 | |
int main() | |
{ | |
int x=2,y=3; | |
cout<<"調用前:x="<<x<<",y="<<y<<endl; | |
swap(&x,&y); // 實參為變數的地址 | |
cout<<"調用後:x="<<x<<",y="<<y<<endl; | |
return 0; | |
} |
# 帶回函式中的多個值
計算一維數組元素的平均值,並能帶回數組中的最大值與最小值。
其中:
- s - 一维数组
- n - 数组中元素个数
- max - 指向最大值
- min - 指向最小值
- 將平均值作為函數返回值
double faver(int s[],int n,int *max,int *min) | |
{ | |
// 變數定義即初始化 | |
double aver=s[0]; | |
*max=*min=s[0]; | |
for(int i=1;i<n;i++) | |
{ | |
aver+=s[i]; | |
if(s[i]>*max) | |
{ | |
*max=s[i]; | |
} | |
if(s[i]<*min) | |
{ | |
*min=s[i]; | |
} | |
} | |
return aver/n; | |
} | |
int main() | |
{ | |
int a[5]={80,89,67,76,98},max,min; | |
double aver; | |
aver=faver(a,5,&max,&min); // 調用函式 | |
cout<<"max="<<max<<"\n"<<"min="<<min<<endl; | |
cout<<"aver="<<aver<<endl; | |
return 0; | |
} |
# 返回指標的函式
<資料型態> *<函式名>(<形式参數表>) | |
{ | |
<語句序列> | |
} |
<資料型態> *
- 為函式的返回值類型,是一個指標類型。
# 例子:返回字元串
編寫函式,返回字元串中首次出現的非空格字元開始的字元串。
如: " I am very excited;"
返回 "I am very excited;"
// 返回字元指標的函式 | |
char *noblank(char *str) | |
{ | |
while(*str==' ') { | |
str++; | |
} | |
return str; | |
} | |
int main() | |
{ | |
char *s1=" I am very excited;", *s2; | |
s2=noblank(s1); | |
cout<<s2<<endl; | |
return 0; | |
} |
# 指向函式的指標變數
使用指向函式的指標變數可以存放函式的指標。
<函式返回值類型> (*<指標變數名>) (<形參型態表列>); |
函式名就是函式的地址,也就是函式的指標。
例如:定義指向 double
型函式的指標變數,該函式有一個 double
型參數
double (*pf)(double ); | |
pf = sqrt; //pf 指向一個平方根函式 |
這時,使用 *pf
可以調用該函式。
cout<<(*pf)(2.0)<<endl; // 輸出根號 2 的值,與下方表達式等價 | |
cout<<sqrt(2.0)<<endl; |