指針是C或C++中的一大難題,因此弄懂指針對C和C++的學習有很大的幫助,最近一直在研究指針,因此寫一篇隨筆把心得記錄一下。
簡單來說指針也是一種變量,只不過指針變量所存儲的不是我們直觀上看到的,而是內存中的地址。如:
我聲明了一個整型變量a並初始化為5,聲明一個整型指針變量b,並且把a的地址賦給它,因此如果我們直接輸出b的話就會得到a的地址,而輸出*b就會得到a的值。
注意我的聲明語句, int *b; int說明這是整數類型的變量,而*表明這是一個指針變量,合起來就是b是一個整型指針變量,變量名是b而不是*b.這一點很重要。
因此指針變量的聲明方法為:
1 type *variableName;
type是數據類型,variableName是變量名。
這是很簡單的一個指針變量的例子,復雜一點的話,我們看看另一種類型的指針:指向指針的指針。如:
1 #include <iostream> 2 3 using namespace std; 4 5 int main() { 6 int num = 5; 7 int *a = # 8 int **b = &a; 9 cout << b << " = " << &a << endl; 10 cout << *b << " = " << a << endl; 11 cout << **b << " = " << *a << endl; 12 return 0; 13 }
上例中我先生命了一個int並初始化為5,然后聲明一個指針變量a並把num的地址賦值給它,然后再聲明一個指針變量b並把a的地址賦值給它,分析一下上述程序會輸出什么呢?
首先第一行輸出,b=a的地址,因為我們賦值的時候就是這么賦值的,這很好理解。
第二行輸出num的地址=num的地址,為什么呢?我們看看,a的值是什么?沒錯,是num的地址,那么*b是什么?當然就是a的地址存儲的東西,那是什么呢?不就等於a嗎?
第三行輸出5=5,首先*b = &num, 那么*(*b)不就是&num中存儲的東西嗎?那不正是num,所以輸出5=5。
還有一個要點就是數組,數組名本身就是一個指針。
1 #include <iostream> 2 3 using namespace std; 4 5 int main() { 6 int a[5] = {1, 2, 3, 4, 5}; 7 int *b = a; 8 cout << a << endl; 9 cout << b << endl; 10 return 0; 11 }
運行程序可以看到輸出兩行一樣的地址。
二維數組稍有不同,不同點在於二維數組本身是一個指針數組:
1 #include <iostream> 2 3 using namespace std; 4 5 int main() { 6 int a[2][3] = {{1, 2, 3}, {4, 5, 6}}; 7 int (*b)[3] = a; 8 int *c = a[0]; 9 cout << a << " " << b << endl; 10 cout << *(a + 1)[0] << " " << *(b + 1)[0] << endl; 11 cout << *c << endl; 12 return 0; 13 }
b和c的區別在於b是指針數組,包括了(*b)[0]、(*b)[1]、(*b)[2],而c只是一個指針變量,指向數組a的第一個元素的位置。
如圖所示:(多維數組同理)
然后我們再看看什么是指針函數。指針函數的定義和指針變量差不多,如
1 int func1(); // 聲明一個函數,返回值為int類型 2 int *func2(); // 聲明一個函數,返回值為int類型指針,指向一個int的地址
我們可以看一個例子:
1 #include <iostream> 2 3 using namespace std; 4 5 6 // 指針函數 7 int *square(int &a) { 8 int *s = new int; 9 *s = a * a; 10 return s; 11 } 12 13 int square1(int &a) { 14 int s1 = a * a; 15 return s1; 16 } 17 18 int main() { 19 int num = 5; 20 cout << "invoke square:" << endl; 21 cout << *square(num) << endl; // 可以理解為cout << *s << endl; 22 cout << endl; 23 cout << "invoke square1:" << endl; 24 cout << square1(num) << endl; 25 cout << endl; 26 return 0; 27 }
上述程序會輸出:
invoke square:
25
invoke square1:
25
可以看出,指針函數的用法和指針變量差不多,只不過多了參數(不一定有參數,但函數名后面的括號一定不能漏)
然后我們再看看函數指針,函數指針也是一個指針變量,與普通的指針變量不同的是它指向的是一個函數的地址,如:
#include <iostream> using namespace std; // 指針函數 int *square(int &a) { int *s = new int; *s = a * a; return s; } int square1(int &a) { int s = a * a; return s; } int main() { int num = 5; int *(*pSquare)(int &a); int (*pSquare1)(int &a); pSquare = square; pSquare1 = square1; cout << "invoke square:" << endl; cout << *(*pSquare)(num) << endl; cout << endl; cout << "invoke square1:" << endl; cout << (*pSquare1)(num) << endl; cout << endl; system("pause"); return 0; }
對比一下pSquare和pSquare1我們會發現區別,pSquare是一個指向指針的指針,而pSquare1是一個指向函數的指針,所以pSquare與square搭配,pSquare1與square1搭配。