我曾說過,在C語言中只有一維的數組(這是我對數組的看法),而且數組元素可以是任何類型的資料(或對象),自然也可以是另外的一個數組(因為數組也是一種資料類型)。所以如果你堅持要說有多維陣列,那也不是不可能的事情。我們只要把一個數組賦值給另一個數組的元素就可以了。當然了,我們必須保證在程式編譯期數組的大小是一個固定的常數。
其實,數組的操作很簡單的。只要我們確定一個數組的大小和指向該數組下標為0的元素的指標,其他的任何一個數組下標的運算都等同於一個對應的指標運算,所以我們說“數組和指標是可以相互操作的”。兩者的本質是一樣的。甚至我們還可以把數組看作是一個“指標”的集合。
我可以通過如下的方式聲明一個數組:
char name[10];
這個語句聲明了name是一個擁有10個字元型元素的數組。類似的
strUCt student{
int tid[4];
char name[10];
char sex;
char address[25];
} std[100];
這裡聲明了std是一個擁有100個元素的數組,而且std中的每一個元素都定義了一名學生的基本資料,每一個元素都是一個結構,其中包括一個擁有4個整形元素的數組(tid[4]),用來記錄學生的學好;還有一個擁有10個字元型元素的數組(name[10]),用來記錄學生的名字;一個用來記錄學生性別的字元(sex);還有一個記錄學生住址,擁有25個字元型元素的數組(address[25])。數組是一個很靈活的結構。
所謂的“二維數組”或“矩陣”是很容易聲明的,例如:
int week[7][24];
這裡把聲明week聲明為一個擁有7個數組元素的數組(這樣解釋,不會感覺奇觀吧),其中每一個元素都是擁有24個整數型元素的數組。注意了不能把week理解為一個擁有24個數組元素的數組,其中每一個元素是一個擁有7個整形元素的數組。 還有,如果week不是用於sizeof的運算元,那麼它總是被一個指向week數組起始地址的指標。這裡又和指標磨合了。 如果一個指向的是一個數組的一個元素,那麼我們只需給這個指標加上一個自然數i(0 =<i <數組的上邊界的值),那麼就可以得到一個指向該數組的弟i個元素的指標。如果在此基礎上減去1,那麼就得到了一個指向前一個元素的指標。這樣的操作很簡單很靈活的。但是這兒也有一個誤區:好多人都認為“給一個指標加一個整數,就等同於給該指標的位元表示加上一個同樣的整數”。其實,這是一個很容易犯的錯誤了,至少在初學C語言的時候,我就犯過這個錯誤,而且不僅一次。其實,這兩者的含義是截然不同的。假設我們有一個這樣的指標聲明語句:
int *p;
那麼p自然是一個指向整數指標了,那麼p+1指向的是電腦記憶體的下一個整數,而不是指向指向地址的下一個記憶體位置。也就是說程式的邏輯地址一般都不同於實際的物理地址。
如果有兩個指向同一個數組的元素,那麼我們可以通過這兩個指標之間的算術運算得到一些有意義的運算式。 比如,
int *pointer;
int *ip = pointer + i;
那麼我們可以通過指ip-pointer得到i的值。如果ip和ponter指向的不是同一個元素,那麼我們就無法保證這個操作的正確性,雖然他們在記憶體位址上相差一個整數倍。
讓我們通過下面的一個例子來看看數組和指標操作的等效性和靈活度:
如果我們在程式中聲明了以下兩個語句,
int a[12];
int *p;
那麼我們可以對數組和指標進行相應的操作了:
(1) p = a;
因為a = a[0],所以這裡就有p=a[0]了,即p和a都指向數組的第一個元素;
(2) p = p + 1;
這也是正確的。它等效於p = a[1];
(3) p++;
這個語句等效於 p = a[2];
還有:
p = &a; 這樣的語句ANSI C中是錯誤的,這一點在前一篇文章我已經聲明過,因為這兩個運算元的類型很顯然是不匹配的,即&a是一個指向數組的指標而p是一個整型指標。所以此類操作是非法的。有時可能會僥倖的通過(因為有些編譯器供應商不一定嚴格的按照ANSI C的保准來開發自己的編譯器),但是我們不提倡這種做法。
數組元素的引用
這是一個足夠讓人糊塗的問題。先看一看下面這個語句是否正確: