有關指標和陣列的理解

2022-08-31 11:51:08 字數 3438 閱讀 2740

下面這四個變數宣告代表四個不同含義:

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...