指標與二維陣列 高階指標入門

2021-10-21 07:26:11 字數 4469 閱讀 4937

注意,對高階指標的學習具有兩面性,一方面可以提高工作效率,另一方面如果運用不到位的話很可能會帶來意想不到的麻煩,以下內容由淺入深逐漸分析,純屬個人探索研究,如有不足多多指正。

一、二維陣列元素的指標表示形式

這裡我先定義乙個二維陣列,如下所示:

int a[3][4] = ;
1000(1)

1004(2)

1008(3)

1012(4)

1016(5)

1020(6)

1024(7)

1028(8)

1032(9)

1036(10)

1040(11)

1044(12)

1. 對於二維陣列,各行的首位址稱為「行位址」,各元素的位址稱為列位址;

2. 按照c語言的規定,二維陣列名a的位址是a[0]的位址,即行位址;

3. 但是注意,雖然a與a[0]的位址相同,但含義不一樣,具體解釋為: 陣列名a可以在其後加數字,變成相應的行位址,例如a+1 = &a[1],a+2 = &a[2],可以說是a能夠行選擇; 行位址a[0]也可以在後邊進行加1選擇,但卻不是行選擇,而是列選擇,例如a[0]+1 = &a[0][1],a[0]+2 = &a[0][2];

4. 因此對於行選擇:* (a+i)=a[i];

5. 因對於列選擇: * (a[i]+j)=a[i][j];

6. 綜合來講就是:* (* (a+i)+j) = * (a[i]+j) = a[i][j];

二、行指標與二階指標(上)

(1)根據二維陣列我們引出了行指標,這裡我們專門討論一下行指標。首先我們有以下**:

int a[3][4] = ;

int (*q)[4]; //定義乙個行指標

q = a;

printf("%d\n", q);

printf("%d\n",q + 1);

這裡給出執行結果:

分析:

1. 上邊說過,a的位址就是a[0]的位址,所以a可以看作是乙個行位址;

2. 既然是行位址,所以同種型別賦值沒什麼不妥;

3. 但是注意,int (*a)[4]中的()不能去掉,因為 的優先順序比 * 高。若為int *p[4],則p首先與結合為陣列,再與 * 結合,此時的p是用來存放指標的陣列,即指標陣列,就不是行指標了;

3. q此時是a[0]的位址,所以輸出16316924是應該的,q+1進行了行選擇,一次跨越了4個int元素,所以q+1輸出是16316940是正確的,提醒一下,每個int型別佔據4個位元組;

(2)我們繼續對行指標深入,有以下**:

int a[3][4] = ;

int(*q)[4]; //定義乙個行指標

q = a;

printf("%d\n", *q);

printf("%d\n", *(q + 1));

這裡給出執行結果:

分析:

1. 可能有人會疑惑q裡放的是a[0]的位址,* q應該能取到a[0][0]的值,但是並非如此;

2. 因為q是行指標,行指標是二級指標,所以如果要取到值的話需要進行兩步 * 運算;

3. 如果這裡再加一行:printf("%d\n", *a[0]);;那麼此時輸出的值就是1了;

4. 有人會在這裡疑惑一下,a[0]是行指標,行指標不應該進行兩次 * 運算才可以取到值嗎? 但注意a的含義,a是乙個陣列名,對於乙個二維陣列,a[0]是乙個行指標沒錯,但它卻是乙個偽二級指標,偽二級指標的含義就是如果此時存的位址能取到值,那麼進行 * 運算時就直接取值;

5. 所以如果你在嘗試進行 ** a[0]進行運算時,編譯肯定都是過不去的,因為*a[0]是乙個確定值,對乙個值進行 * 運算是一定會錯的;

6. 特別的,如果是陣列名參與的運算,需要先降級到行指標,再取值,**這個:因為a+1 = &a[1],a+2 = &a[2],注意那個 & 運算,所以對於a想要求出它的值時需要 **a, 對於a+1也是如此;這裡可以作以認證:

二、行指標與二階指標(下)

(1)接下來我們將行指標變形一下,有如下**:

int a[3][4] = ;

int(*t)[1]; //定義乙個行指標

t = (int(*)[1])a;

printf("%d,%d,%d\n",t,*t,**t);

執行結果如下:

分析:

1. 如果忽略賦值那一步操作整體來看,輸出結果沒什麼問題,和上邊講的一樣;

2. 但是賦值這個地方需要注意,雖然定義的是乙個行指標,但行指標的列數與陣列a的列數並不匹配,所以這個時候需要進行乙個強制型別轉換,曾經我們遇到過這樣的語句:int a = (int) 『a』 ;理所應當,這裡的int(*)[1]也是一種強制轉換的格式;

3. 將乙個二維陣列型別強制轉換成乙個列數只有1的行指標型別,答案只有乙個,那就是變成了12行:

printf("%d,%d\n",*t,*(t + 1));

printf("%d,%d\n", **t, **(t + 1));

printf("%d,%d,%d\n", **(t + 2), **(t + 3), **(t + 11));

執行結果如下:

4. 前邊說過行指標後邊加數字就會進行行選擇,因為這裡變成了12行,所以這樣的結果並不與前面知識矛盾;

5. 當然這裡你也可以用列選擇進行輸出,例如:* (t[0]+1)的結果是2, * (t[1]+1)的結果是3,因為行不夠會繼續往下找,行指標如此,二維陣列也是如此,如:*(a[0]+4)的結果是5;

三、二階指標

(1)下面開始二階指標的深入,有如下**:

int a[3][4] = ;

int** p;

p = (int**)a;

printf("%d,%d\n", p, p + 1);

printf("%d,%d\n", a, a + 1);

printf("%d,%d\n", *(p), *(p + 1));

執行結果如下:

1. 首先來看一下賦值的地方,p是乙個二級指標,a是乙個二維陣列名,位址與a[0]相同,但由於是偽二級指標,所以賦值給p的時候需要進行一下型別轉換,也就是(int**);

2. 輸出a與a+1都很正常,前者是第一行的位址,後者進行行選擇後第二行的位址;

3. 將a的位址賦值給二級指標p, 按說p的位址是17825020,p+1的位址是17825024,但為什麼p+1的實際位址和想象中的對不上呢?

4. 注意,二級的指標變數以及多級的指標變數,如果不是行指標,那麼它和普通指標在算術運算方面是相似的,就是說此處p+1,只往後增加了乙個元素;

(2)下邊我們進行最純粹的二級指標學習,有以下**:

int a[3][4] = ;

int** p;

int* m = &a[1][1];

p = &m;

printf("%d,%d\n", p, p + 1);

printf("%d,%d\n", *(p), *(p + 1));

printf("%d\n", **(p));

執行結果如下:

1. 這裡的p是乙個正宗的二級指標,指向的是陣列元素a[1][1];

2. m存放的是a[1][1]的位址,p存放的是m的位址,可以說p存放的是a[1][1]位址的位址,所以在p的位址上加一會是**,這裡的結果是不可控的,也是沒有意義的,至於想要輸出這個結果所對應的值,更是不可能的;

高階指標的入門就到這裡,本篇文章有諸多難點,建議收藏多次檢視。

二維陣列 指標陣列與陣列指標

一 首先我們從字面意思理解一下什麼是指標陣列什麼是陣列指標 1 指標陣列 本質是乙個陣列,陣列中的每乙個元素是乙個指標。2 陣列指標 本質是乙個指標,而指標指向乙個陣列。二 我們該怎麼區分指標陣列和陣列指標?1 總共有三種表示形式 int p 4 和int p 4 和int p 4 表面看起來是不是...

二維陣列與二維指標

1.二維陣列的儲存是線性的,可以通過一維指標的方式訪問。如一下 int map 5 5 int mapd map 0 0 則 map i j mapd i 5 j 而利用二維陣列線性儲存的特性,可以將二維陣列當作一維指標方便的在函式之間傳遞 如 將乙個二維陣列賦值給乙個動態二維陣列,引數設定為一維指...

二維陣列與二維指標

一.指標與二維陣列 以martix 3 4 為例 1.二維陣列的本質 int martix 3 4 int martix 3 4 int 4 martix 3 令int 4 為type,type martix 3 為含有三個元素的陣列,每乙個元素型別為int 4 int 4 是乙個擁有4個int型別...