二維陣列
c語言按照行主序儲存二維陣列。也就是說,二維陣列元素在記憶體中的位置是連續的,每行末尾元素(若不是最後一行)的下一個元素就是下一行的首元素。
如下圖所示
接下來我們來分析一下如何將二維陣列所有元素初始化零。
假設陣列的宣告如下:
int a[NUM_ROWS][NUM_COLS];
普通的寫法是利用兩層for迴圈
int row, col;
for (row = 0; row < NUM_ROWS; row++)
for (col = 0; col < NUM_COLS; col++)
a[row][col] = 0;
我們可以利用指標操作,將二維陣列看成一個一維的大陣列,其元素數量為NUM_ROWS*NUM_COLS,利用一個for迴圈完成操作
int *p;
for (p = &a[0][0]; p <= &a[NUM_ROWS-1][NUM_COLS-1]; p++)
*p = 0;
不過雖然程式碼量減少了,但實際上程式執行的次數和前者兩層for迴圈操作執行次數是一樣的。(這類方法明顯破壞了程式的可讀性,但是至少對一些老的編譯器來說這種方法在效率方面進行了補償。不過,對許多現代的編譯器來說,這樣所獲得的速度優勢往往極少甚至完全沒有。)
接下來我們再看一個例子:將二維陣列第i行的元素置0
為了訪問到第i行的元素,讓p指向陣列a中第i行的第一個元素:
p=&a[i][0];
實際上,我們還可以將這句程式碼簡寫為
p=a[i];
對於任意一維陣列a[]來說,其首元素地址為a。而二維陣列可以看成是多個一維陣列,行數就是一維陣列的個數,列數就是陣列中元素的個數。由此第i行的首元素地址就為a[i]。
如果要正經推導的話:對於任意陣列a來說,表示式a[i]等價於(a + i)。因此&a[i][0]等同於&((a[i] + 0)),而後者等價於&a[i];又因為&和運算子可以抵消,也就等同於a[i]。
那麼程式碼為:
int a[NUM_ROWS][NUM_COLS], *p, i;
for (p = a[i]; p < a[i] + NUM_COLS; p++)
*p = 0;
接下來我們再來思考一下怎麼將陣列a的第i列的元素置零呢?
我們可以利用陣列指標(指向陣列的指標)來實現這點。如宣告一個陣列指標:int (*p)[NUM_COLS]
。
我們知道,c語言指標每次自增1時,記憶體地址增加的量即為指標指向型別的所佔記憶體單元數。在這裡,p指向一個元素個數為NUM_COLS的int型陣列,那麼p++將會導致p指向地址增加NUM_COLS*(int型所佔地址單元個數),這就實現了p從這一行指向了下一行。
程式碼如下
for(p = &a[0]; p < &a[NUM_ROWS]; p++){
(*p)[i] = 0;
}
最後,如果我們想遍歷整個陣列的話,也可以將整個二維陣列看成一整個一維陣列,利用指標進行遍歷。
int *t;
for(t = a[0]; t <= &a[NUM_ROWS-1][NUM_COLS-1]; t++)
printf("%d ",*t);