指針是某個變量的地址,是一個地址。
指針變量是存放指針(某個變量地址)的變量,是一個變量。
指針變量是一個變量,也有它自己的地址;這幾句話對理解指針非常有幫助。
舉例:
int c = 76; int *pointer = &c;
普通變量 c 和 指針變量 pointer 在內存中的形式如下圖:
;
指針變量pointer 有它自己在內存中的地址,見上圖黃色區域,指針變量的值存放著一個地址,見上圖紅色方框中的藍色方框中的地址,這個地址指向變量c,也即這個地址和變量c的地址相等;
我們把c,c的地址,*pointer,pointer,pointer的地址分別輸出,見下列代碼:
cout << c << endl; //輸出:76 cout << *pointer << endl; //輸出:76 cout << hex << &c << endl; //輸出:0x0012FF74 cout << pointer << endl; //輸出:0x0012FF74 cout << &pointer << endl; //輸出:0x0012FF90
#---------------------------------------------------------------------------------#
指針基類型的作用:當用指針遍歷時,+1等於幾個byte取決與指針基類型;
舉例:
;
如上圖,指針p2 指向某個int值,int值占據4個byte大小(有些環境下占2個byte),那麼p2++的值是在p2的值的基礎之上加上4個byte找到的。
#---------------------------------------------------------------------------------#
數組與指針
數組名相當於指向數組第一個元素的指針。
對於int a[4] = {1,3,5,7};
a是指向數組第一個元素的指針,即a相當於&a[0];
&a是"指向數組"的指針,&a+1將跨越16個字節;
&a相當於管轄范圍上升了一級;
*a是數組的第一個元素a[0], 即*a等價於a[0];
*a相當於管轄范圍下降了一級;
來看代碼,這個例子我問過兩位師兄,都沒能答對。注意標紅色的兩條輸出的區別。
#include<iostream> #include<iomanip> using namespace std; int main() { int a[4] = {1,3,5,7}; cout << hex << a << endl; //輸出:0028F7C4 cout << &a << endl; //輸出:0028F7C4 cout << &a+1 << endl; //輸出:0028F7D4 cout << *(&a) << endl; //輸出:0028F7C4 cout << *(&a)+1 << endl; //輸出:0028F7C8 }
這是數組a在內存中的存放形式,非常有助於理解。
如果換成二維數組,情況也類似,只是稍微復雜些;
;
來看個例子:
#include<iostream> #include<iomanip> using namespace std; int main() { int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; cout << hex << a << endl; //輸出:0xbf870830 cout << &a[0] << endl; //輸出:0xbf870830 cout << a+1 << endl; //輸出:0xbf870840 cout << &a[0]+1 << endl; //輸出:0xbf870840 cout << *a << endl; //輸出:0xbf870830 cout << a[0] << endl; //輸出:0xbf870830 cout << &a[0][0] << endl; //輸出:0xbf870830 cout << *a+1 << endl; //輸出:0xbf870834 cout << a[0]+1 << endl; //輸出:0xbf870834 cout << &a[0][0]+1 << endl; //輸出:0xbf870834 cout << &a+1 << endl; //輸出:0xbf870860 }
第一次做這個題目幾乎很難都答對,但知道了規則之後就都能理解了,要更深入了解數組跟指針的關系和區別的話還得看其他的書。
小結一下:
數組名相當於指向數組第一個元素的指針。這裡第一個元素不單單只一個數,可能是一個小數組(如上例);
對於二維數組a,見下圖;
a相當於指向數組的第0行那個小數組;
*a等價於a[0], 相當於讓a下降了一級;
&a表示“指向二維數組”的指針,相當於上升的一級;
#---------------------------------------------------------------------------------#
當指針用作函數返回值時,必須保證返回的地址是有意義的!
舉例:
#include<iostream> using namespace std; int *getInt1() { int value1 = 20; return &value1; } int *getInt2() { int value2 = 30; return &value2; } int main() { int *p, *q; p = getInt1(); q = getInt2(); cout << *p << endl; //輸出: 30 return 0; }
上述代碼,編譯出現警告。指針變量p存放了一個局部變量的地址,而局部變量的作用域只在函數內部,函數調用結束後即被釋放(這半句話的表述不夠准確,水平有限,暫時只能這麼描述)。
解決辦法: 將局部變量變為靜態局部變量即可。或者也可以設為全局變量(不過這明顯不是個好主意)。
int *getInt1() { int static value1 = 20; return &value1; }