·引 對數組的認知
在c語言中,我們經常使用的一個結構便是數組,在最開始學習數組的時候,它被描述成這樣(以一維二維數組為例):
一維數組是若干個數連續排列在一起的集合,我們可以通過0-N的標記(N為數組的長度)來訪問每一個元素。
二維數組則是一維數組的集合。
所以在最開始我們對二維數組的概念是這樣的:
然后推而廣之到三維數組
很合理的,我們通過**空間結構**去類比數組的一維與二維,那么問題來了,在計算機當中它又是怎么“類比”這些數組的呢?
我們先看一些代碼
#include <stdio.h> int main(void) { int a[5][5]; for(int i=0,num=0;i<5;i++) for(int j=0;j<5;j++,num++) a[i][j]=num; for(int i=0;i<5;i++){ for(int j=0;j<5;j++) printf("%5d",a[i][j]); printf("\n"); } printf("\na[ 1][ 1]=%2d %p\n",a[1][1],&a[1][1]); printf("a[ 1][ 2]=%2d %p\n",a[1][2],&a[1][2]); printf("a[ 1][ 3]=%2d %p\n",a[1][3],&a[1][3]); } ``` ``` 運行結果: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 a[ 1][ 1]= 6 000000000062FDE8 a[ 1][ 2]= 7 000000000062FDEC a[ 1][ 3]= 8 000000000062FDF0
這個結果是顯而易見的,而通過對地址的觀察,我們發現每兩個相鄰的數其間距為4個字節,也驗證了我們認為它是連續的這一認知。而按照約定進行訪問也是我們一般的使用方法。
· 擴展
接下來我們將輸出本部分替換成以下代碼
//這里我們將研究標記如果使用負數將會是什么情況 printf("a[ 0][ 0]=%2d %p\n",a[0][0],&a[0][0]); printf("a[ 0][-1]=%2d %p\n",a[0][-1],&a[0][-1]); printf("a[-1][ 0]=%2d %p\n",a[-1][0],&a[-1][0]); printf("a[-1][-1]=%2d %p\n",a[-1][-1],&a[-1][-1]); ``` 一次運行實例 ``` a[ 0][ 0]= 0 000000000062FDD0 a[ 0][-1]= 0 000000000062FDCC a[-1][ 0]= 0 000000000062FDBC a[-1][-1]= 0 000000000062FDB8 ``` 或者我們再對a[4][4]進行越界研究,代碼: ``` printf("a[ 4][ 4]=%2d %p\n",a[4][4],&a[4][4]); printf("a[ 4][ 5]=%2d %p\n",a[4][5],&a[4][5]); printf("a[ 5][ 4]=%2d %p\n",a[5][4],&a[5][4]); printf("a[ 5][ 5]=%2d %p\n",a[5][5],&a[5][5]); ``` 一次運行實例 ``` a[ 4][ 4]=24 000000000062FE30 a[ 4][ 5]= 0 000000000062FE34 a[ 5][ 4]= 5 000000000062FE44 a[ 5][ 5]=25 000000000062FE48 ```
實際上這些結果是恰恰符合我們的預期的,因為他們使用的下標超出了數組范圍,所以自然訪問到了數組外內存中的數,這些數是大部分是隨機的。
就像這樣
但是對於以下這些代碼:
``` printf("a[ 1][ 0]=%2d %p\n",a[1][0],&a[1][0]); printf("a[ 1][-1]=%2d %p\n",a[1][-1],&a[1][-1]); printf("a[ 1][-2]=%2d %p\n",a[1][-2],&a[1][-2]); ```
其輸出結果為
``` a[ 1][ 0]= 5 000000000062FDE4 a[ 1][-1]= 4 000000000062FDE0 a[ 1][-2]= 3 000000000062FDDC ```
考慮之前的類比,這樣的結果顯然是不合理的,因為如果是二維結構,那么我們所輸出的結果應該為一個內存中的隨機值,但是根據觀察原數組:
``` 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ```
我們恰恰可以發現它a[1][-1]與a[1][-2]輸出的恰恰是a[0][4]與a[0][3]的內容。也就是說我們退回了上一行
其實這些問題的答案在觀察數組的地址時就能找到答案:
000000000062FDE0 - 000000000062FDE4= 4 = sizeof(int)
顯然這意味着這是內存空間中連續的地址,也就是說二維數組真正的儲存方式任然是線性的,一維的,同理我們可以得知對於三維,乃至更高維的數組,它其實也無法跳出維度的限制,其實他們都是一維
所以我們應該這樣認識多維數組
(其實這些都是很簡單的東西,但是為此總結一下深化一下印象。因為很多時候第一印象往往是錯的,正如二維數組並不是二維)