指針就是指向變量的地址,而引用是變量的別名,通過指針或引用都可以修改變量的值,但兩者的使用上會有一些差異,比如:
- 引用在定義的時候必須初始化,且只能指向一個變量,後續不能指向其它變量。而指針在定義的時候可以不初始化,且後續可以修改指向爲其它地址;
- 引用的大小是所指向變量的大小,而指針的大小則是固定的,32位系統爲4字節,64位系統位8字節;
- 引用比指針更安全,因爲引用在定義的時候必須初始化,所以不可能爲空,而指針可能爲空,所以指針使用前必須判空;
- 引用可以直接使用,而指針需要用*;
還是通過代碼來理解,定義了幾個函數:
void print(int *pn)
{
cout<<"print(int *pn): pn\t"<<pn<<endl;
cout<<"print(int *pn): &pn\t"<<&pn<<endl;
cout<<"print(int *pn): *pn\t"<<*pn<<endl;
*pn = 12;
}
void print(int &pn)
{
cout<<"print(int &pn): pn\t"<<pn<<endl;
cout<<"print(int &pn): &pn\t"<<&pn<<endl;
pn = 13;
}
void print2(int *&pn)
{
cout<<"print2(int *&pn): *pn\t"<<*pn<<endl;
cout<<"print2(int *&pn): &pn\t"<<&pn<<endl;
cout<<"print2(int *&pn): pn\t"<<pn<<endl;
*pn = 14;
}
int n = 10;
int *pn = &n;
cout<<"例子1: 傳指針 ---------->"<<endl;
print(pn);
cout<<__func__<<"\tpn\t"<<pn<<endl;
cout<<__func__<<"\t&pn\t"<<&pn<<endl;
cout<<__func__<<"\t*pn\t"<<*pn<<endl;
cout<<"例子2: 傳引用 ---------->"<<endl;
print(*pn);
cout<<__func__<<"\tpn\t"<<pn<<endl;
cout<<__func__<<"\t&pn\t"<<&pn<<endl;
cout<<__func__<<"\t*pn\t"<<*pn<<endl;
cout<<"例子3: 傳指針引用 ---------->"<<endl;
print2(pn);
cout<<__func__<<"\tpn\t"<<pn<<endl;
cout<<__func__<<"\t&pn\t"<<&pn<<endl;
cout<<__func__<<"\t*pn\t"<<*pn<<endl;
輸出結果:
例子1: 傳指針 ---------->
print(int *pn): pn 0x7ffeed4af9b4
print(int *pn): &pn 0x7ffeed4af828
print(int *pn): *pn 10
main pn 0x7ffeed4af9b4
main &pn 0x7ffeed4af9a8
main *pn 12
例子2: 傳引用 ---------->
print(int &pn): pn 12
print(int &pn): &pn 0x7ffeed4af9b4
main pn 0x7ffeed4af9b4
main &pn 0x7ffeed4af9a8
main *pn 13
例子3: 傳指針引用 ---------->
print2(int *&pn): *pn 13
print2(int *&pn): &pn 0x7ffeed4af9a8
print2(int *&pn): pn 0x7ffeed4af9b4
main pn 0x7ffeed4af9b4
main &pn 0x7ffeed4af9a8
main *pn 14
在例子1中,print(int *pn)函數和main函數輸出的&pn是不一樣的,一個是0x7ffee9fa9838,一個是0x7ffee9fa99a8,因爲print(int *pn)函數是傳值,沒錯,傳值,只是這個值是“指針”,它會生成一個指針的副本,因此print(int *pn)函數和main函數輸出的&pn會不一樣。
注意⚠️,還有一個容易忽視的錯誤,看代碼:
void testPtr(int *pi)
{
pi = new int;
cout<<__func__<<"\t"<<pi<<endl;
}
int main() {
int *pi = new int(100);
cout<<"pi -> "<<pi<<endl;
testPtr(pi);
cout<<"pi -> "<<pi<<endl;
}
運行結果:
pi -> 0x7fa03b402ae0
testPtr 0x7fa03b402af0
pi -> 0x7fa03b402ae0
可能有人會認爲在testPtr能夠修改pi的值,但正如上面所說的,指針是傳值,作爲testPtr的參數時,是生成了一個指針的副本,因此在testPtr函數內,修改的是指針副本的值,而不是main函數中定義的pi的值。
還有一個關於引用的例子,看代碼:
int &max(int &a, int &b)
{
return a > b ? a : b;
}
int n1 = 11, n2 = 12;
cout<<++max(n1,n2)<<"\t"<<n1<<"\t"<<n2<<endl;
程序輸出:
13 11 13
max函數返回的是n2的引用,因此++max(n1,n2)會修改n2的值⚠️。