下面這四個變數宣告代表四個不同含義:
type **a; 指向指標的指標
type a[n1][n2]; 二維陣列
type *a[n]; 指標陣列(即陣列元素是指標)
type (*a)[n]; 指向陣列的指標
1.type **a 代表是指向指標的指標,其實宣告類似「type **...*a」形式的都合法,代表「指向指標的指標的...指標的指標」。
例程:int a = 9;
int * b = &a;
int **c = &b;
int ***d = &c;
int ****e = &d;
int *****f = &e;
printf("value of a is %d\n",a);
printf("address of a is %x\n",b);
printf("address of b is %x\n",c);
printf("address of c is %x\n",d);
printf("address of d is %x\n",e);
printf("address of e is %x\n",&e);
輸出:value of a is 9
address of a is 12ff7c
address of b is 12ff78
address of c is 12ff74
address of d is 12ff70
address of e is 12ff6c
另外,這種型別的指標只能初始化一維陣列,可以初始化形式如 :
type *a = (type *)(malloc(sizeof(type) * n)); //建立一維陣列,元素是type型
type **a = (type **)(malloc(sizeof(type *) * n)); //建立一維陣列,元素是type *型
其實,函式malloc(n)只關注引數n的值,n代表申請的位元組數,不論n有多大,malloc一概返回void *指標,
除非堆空間記憶體不夠時返回null。前面再加上強制型別轉換,使返回值變成想要的型別(只要它和void * 可以強制轉換)。
就算你寫成 int a = (int)(malloc(1000));
單看這一條語句編譯器不會報錯,沒有型別寬度檢查。
申請一塊記憶體想讓它以什麼方式被編譯器認可,編譯器就以什麼方式認可,至於以後會不會出錯人家不管。
又由於,編譯器對"type **...*a"這種方式宣告的變數最多按照一維陣列處理,即:
type * a = (type *)(malloc(...)),a[m]是type型
type **a = (type **)(malloc(...)), a[m]是type *型
type ***a = (type **)(malloc(...)), a[m]是type **型
...以上語句後,出現「a[m][n]」會出錯!!
所以只能初始化一維陣列,不管指標指向多大空間,都安一維陣列處理。
2.a[n1][n2]代表乙個二維陣列,陣列可以使任意維度,宣告類似「a[n1][n2]...[nm]」都合法,代表m維陣列。
以整型二維陣列為例:int a[n1][n2]初始化方法有兩種,
靜態初始化:a[n1][n2] = ,
,...
}; 動態初始化:(後面再提);
靜態初始化後,陣列所有元素被分配在程式棧空間內。有以下等式成立:
&a = a = &a[0] = a[0] = &a[0][0];
&a代表叫做a這個名字的變數的位址;a代表陣列a首元素的位址;
由於陣列a是在棧上分配空間的,所以陣列名a這個變數和陣列本身分配在乙個位址上,所以&a = a;
a[0]是陣列首元素,所以&a[0] = a;
a[0]代表陣列a[0]的首元素位址,a[0][0]是a[0]的首元素,所以&a[0][0] = a[0];
其實往簡單了想,a,a[0],a[0][0]都是二位陣列的頭部,所以起始位址是一樣的。
所以靜態初始化的二維陣列:&a = a = &a[0] = a[0] = &a[0][0],永遠成立。
(對於&a, a, &a[0], a[0], &a[0][0]相等與否還有另外兩種情況,後面再提)。
3.type *a[n] 代表乙個陣列,陣列的元素是指標,類似於"type **...*a[n]"的宣告都是合法的,代表陣列的元素是n維指標。
先明確這裡a是乙個陣列,語句 int * a[n]執行後,編譯器在棧區開闢乙個空間,儲存n個指標值。
對於這樣的語句 int * a[10] = (int *[10])(malloc(...));(或int * a[10] = new int*[10];)
是編譯錯誤的,因為不能把乙個void * 型轉化成陣列型,從另乙個角度考慮,陣列可以看做指標常量,不能給乙個常量賦值。
如果一定要在堆區建立指標陣列,可以使用指標的指標:
int **a = (int **)(malloc(...));
也可以使用指標的指標:
(後面再提)。
上面說到,二維陣列的動態初始化,可以用指標陣列完成。
int *a[10];
for(int i = 0; i < 10; ++i)
這樣就完成了動態初始化,建立了乙個10 * 10的陣列,可以用a[n][m]訪問具體元素。
現在分析一下這種情況下&a, a, &a[0], a[0], &a[0][0]的關係:
陣列a在棧區建立,所以 &a = a = &a[0],所有a[i]指向的陣列在堆區建立,所以a[0] = &a[0][0].
即&a = a = &a[0] != a[0] = &a[0][0].
另外a[i]之間的位址,也不一定滿足a[i + 1] - a[i] = 4 * 10,因為每乙個a[i]都是分別建立空間。
4.type (*a)[n],代表指向陣列的指標。「int (*a)[n1][n2]...[nm]」的宣告都是合法的,表示指向m維陣列的指標。
其實,int (*a)[n] 和 int b[n][...],這裡a和b比較類似。a是指標名,b是陣列名。
區別是b是常量,值固定,a是變數,值可變,可以做賦值運算,例如 a = b;
也可以動態初始化二維陣列:
int (*a)[10] = (int (*)[10])(malloc(4 * 10)) 或 int (*a)[10] = new int[...][10];
再來分析一下&a, a, &a[0], a[0], &a[0][0]的關係。
由於變數a在棧區建立,而二維陣列其他部分在堆區建立,所以有
&a != a = &a[0] = a[0] = &a[0][0],而且相鄰a[i]之間的差值一定為 4 * 10。
對於上面提到的,在堆區分配指標陣列問題,可以這樣解決:
int *(*a)[10] = (int *(*)[10])(malloc(10 * 4));
^_^
指標陣列和陣列指標的簡單理解
指標陣列,重點在陣列 陣列指標,重點在指標 例子 include using namespace std int main int a 4 指標陣列 int b 4 陣列指標 b c 將陣列c中元素賦給陣列a for int i 0 i 4 i 輸出看下結果 cout include using n...
理解指標和陣列的關係
int a 3 4 定義乙個三行四列的矩陣 int b 定義乙個指向int的指標 b a 0 將二維陣列也就是矩陣的第乙個位置位址給指標b。說明a 0 儲存的就是個位址,a 0 是乙個行指標a 0 0 的意思就是行指標a 0 的第乙個元素。cout bcout b 4 這時候輸出的是5,這也就證明了...
關於指標和陣列的理解
要充分理解指標和陣列,首先要清楚它們的特性。指標是位址。陣列是一組有序資料的集合,陣列中的資料排列是有一定規律的。指標和陣列在本質上是不同的。下面將介紹指標陣列 陣列指標 函式指標 函式指標陣列 指向函式指標陣列的指標 1.指標陣列 指標陣列是陣列,是乙個存放指標的陣列。如 int arr 10 2...