數(shù)組
數(shù)組由數(shù)據(jù)類型相同的一系列元素組成辩撑。 需要使用數(shù)組時伞辛, 通過聲明數(shù)組告訴編譯器數(shù)組中內(nèi)含多少元素和這些元素的類型沮焕。 編譯器根據(jù)這些信息正確地創(chuàng)建數(shù)組。
/* 一些數(shù)組聲明*/
int main(void)
{
?float candy[365]; /* 內(nèi)含365個float類型元素的數(shù)組 */
char code[12]; /*內(nèi)含12個char類型元素的數(shù)組*/
int states[50]; /*內(nèi)含50個int類型元素的數(shù)組 */
...
}
方括號([]) 表明candy模燥、 code和states都是數(shù)組, 方括號中的數(shù)字表明數(shù)組中的元素個數(shù)掩宜。
要訪問數(shù)組中的元素蔫骂, 通過使用數(shù)組下標(biāo)數(shù)(也稱為索引) 表示數(shù)組中的各元素。
初始化數(shù)組
數(shù)組通常被用來儲存程序需要的數(shù)據(jù)牺汤。只儲存單個值的變量有時也稱為標(biāo)量變量(scalar variable)
用以逗號分隔的值列表(用花括號括起來) 來初始化數(shù)組辽旋,各值之間用逗號分隔。 在逗號和值之間可以使用空格慧瘤。
每4年打錯一個月份的天數(shù)(即戴已, 2月份的天數(shù)) 。 該程序用初始化列表初始化days[]锅减, 列表(用花括號括起來) 中用逗號分隔各值糖儡。符號常量 MONTHS 表示數(shù)組大小
使用const聲明數(shù)組有時需要把數(shù)組設(shè)置為只讀。 這樣怔匣, 程序只能從數(shù)組中檢索值握联, 不能把新值寫入數(shù)組。 要創(chuàng)建只讀數(shù)組每瞒, 應(yīng)該用const聲明和初始化數(shù)組金闽。
在使用數(shù)組元素之前,必須先給它們賦初值剿骨。 編譯器使用的值是內(nèi)存相應(yīng)位置上的現(xiàn)有值代芜。
注意 存儲類別警告
數(shù)組和其他變量類似, 可以把數(shù)組創(chuàng)建成不同的存儲類別(storageclass)浓利。
存儲類別的原因是挤庇, 不同的存儲類別有不同的屬性钞速。
初始化列表中的項數(shù)應(yīng)與數(shù)組的大小一致。
當(dāng)初始化列表中的值少于數(shù)組元素個數(shù)時嫡秕, 編譯器會把剩余的元素都初始化為0渴语。 也就是說, 如果不初始化數(shù)組昆咽,數(shù)組元素和未初始化的普通變量一樣驾凶, 其中儲存的都是垃圾值; 但是掷酗, 如果部分初始化數(shù)組调违, 剩余的元素就會被初始化為0。
如果初始化列表的項數(shù)多于數(shù)組元素個數(shù)泻轰,編譯器會毫不留情地將其視為錯誤翰萨。
如果初始化數(shù)組時省略方括號中的數(shù)字, 編譯器會根據(jù)初始化列表中的項數(shù)來確定數(shù)組的大小糕殉。sizeof運(yùn)算符給出它的運(yùn)算對象的大心豆怼(以字節(jié)為單位) 。 所以sizeof days是整個數(shù)組的大邪⒌(以字節(jié)為單位) 雳锋, sizeof day[0]是數(shù)組中一個元素的大小(以字節(jié)為單位) 羡洁。 整個數(shù)組的大小除以單個元素的大小就是數(shù)組元素的個數(shù)玷过。
指定初始化器(C99)
C99 增加了一個新特性: 指定初始化器(designated initializer) 。 利用該特性可以初始化指定的數(shù)組元素筑煮。
而C99規(guī)定辛蚊, 可以在初始化列表中使用帶方括號的下標(biāo)指明待初始化的元素。
對于一般的初始化真仲, 在初始化一個元素后袋马, 未初始化的元素都會被設(shè)置為0。
初始化器的兩個重要特性,第一秸应, 如果指定初始化器后面有更多的值虑凛,那么后面這些值將被用于初始化指定元素后面的元素。第二软啼, 如果再次初始化指定的元素桑谍, 那么最后的初始化將會取代之前的初始化。
編譯器會把數(shù)組的大小設(shè)置為足夠裝得下初始化的值祸挪。
給數(shù)組元素賦值
聲明數(shù)組后锣披, 可以借助數(shù)組下標(biāo)(或索引) 給數(shù)組元素賦值。
C 不允許把數(shù)組作為一個單元賦給另一個數(shù)組, 除初始化以外也不允許使用花括號列表的形式賦值雹仿。
數(shù)組邊界
在使用數(shù)組時榜跌, 要防止數(shù)組下標(biāo)超出邊界。 也就是說盅粪, 必須確保下標(biāo)是有效的值。
創(chuàng)建了一個內(nèi)含4個元素的數(shù)組悄蕾, 然后錯誤地使用了-1~6的下標(biāo)票顾。
在C標(biāo)準(zhǔn)中, 使用越界下標(biāo)的結(jié)果是未定義的帆调。
該編譯器似乎把value2儲存在數(shù)組的前一個位置奠骄, 把value1儲存在數(shù)組的后一個位置(其他編譯器在內(nèi)存中儲存數(shù)據(jù)的順序可能不同)。使用越界的數(shù)組下標(biāo)會導(dǎo)致程序改變其他變量的值番刊。不同的編譯器運(yùn)行該程序的結(jié)果可能不同含鳞, 有些會導(dǎo)致程序異常中止。
數(shù)組元素的編號從0開始芹务。 最好是在聲明數(shù)組時使用符號常量來表示數(shù)組的大小這樣做能確保整個程序中的數(shù)組大小始終一致
指定數(shù)組大小
#define SIZE 4
int main(void)
{
?intarr[SIZE]; // 整數(shù)符號常量
double lots[144]; // 整數(shù)字面常量蝉绷。
....
}
在C99標(biāo)準(zhǔn)之前, 聲明數(shù)組時只能在方括號中使用整型常量表達(dá)式枣抱。 所謂整型常量表達(dá)式熔吗, 是由整型常量構(gòu)成的表達(dá)式。 sizeof表達(dá)式被視為整型常量佳晶, 但是(與C++不同) const值不是桅狠。
C99引入變長數(shù)組主要是為了讓C成為更好的數(shù)值計算語言。
多維數(shù)組
二維視圖有助于幫助理解二維數(shù)組的兩個下標(biāo)轿秧。在計算機(jī)內(nèi)部中跌,這樣的數(shù)組是按順序儲存的, 從第1個內(nèi)含12個元素的數(shù)組開始菇篡, 然后是第2個內(nèi)含12個元素的數(shù)組漩符, 以此類推。
程序使用了兩個嵌套for循環(huán)驱还。 第1個嵌套for循環(huán)的內(nèi)層循環(huán)陨仅, 在year不變的情況下, 遍歷month計算某年的總降水量铝侵; 而外層循環(huán)灼伤, 改變year的值, 重復(fù)遍歷month咪鲜, 計算5年的總降水量狐赡。
初始化二維數(shù)組
初始化二維數(shù)組是建立在初始化一維數(shù)組的基礎(chǔ)上。
如果某列表中的數(shù)值個數(shù)超出了數(shù)組每行的元素個數(shù)疟丙, 則會出錯颖侄, 但是這并不會影響其他行的初始化鸟雏。
初始化時也可省略內(nèi)部的花括號, 只保留最外面的一對花括號览祖。只要保證初始化的數(shù)值個數(shù)正確孝鹊, 初始化的效果與上面相同。 但是如果初始化的數(shù)值不夠展蒂, 則按照先后順序逐行初始化又活, 直到用完所有的值。 后面沒有值初始化的元素被統(tǒng)一初始化為0锰悼。
因為儲存在數(shù)組rain中的數(shù)據(jù)不能修改柳骄, 所以程序使用了const關(guān)鍵字聲明該數(shù)組。
其他多維數(shù)組
處理三維數(shù)組要使用3重嵌套循環(huán)箕般, 處理四維數(shù)組要使用4重嵌套循環(huán)耐薯。 對于其他多維數(shù)組, 以此類推丝里。
指針和數(shù)組
指針提供一種以符號形式使用地址的方法曲初。使用指針的程序更有效率。 尤其是杯聚, 指針能有效地處理數(shù)組复斥。數(shù)組表示法其實是在變相地使用指針。
第2行打印的是兩個數(shù)組開始的地址械媒, 下一行打印的是指針加1后的地址目锭, 以此類推。
在C中纷捞, 指針加1指的是增加一個存儲單元痢虹。 對數(shù)組而言, 這意味著把加1后的地址是下一個元素的地址主儡, 而不是下一個字節(jié)的地址 這是為什么必須聲明指針?biāo)赶驅(qū)ο箢愋偷脑蛑弧?只知道地址不夠奖唯, 因為計算機(jī)要知道儲存對象需要多少字節(jié)(即使指針指向的是標(biāo)量變量, 也要知道變量的類型糜值, 否則*pt 就無法正確地取回地址上的值) 丰捷。
指針的值是它所指向?qū)ο蟮牡刂贰?地址的表示方式依賴于計算機(jī)內(nèi)部的硬件。 許多計算機(jī)(包括PC和Macintosh) 都是按字節(jié)編址寂汇, 意思是內(nèi)存中的每個字節(jié)都按順序編號病往。 這里, 一個較大對象的地址(如double類型的變量) 通常是該對象第一個字節(jié)的地址骄瓣。
在指針前面使用*運(yùn)算符可以得到該指針?biāo)赶驅(qū)ο蟮闹怠?/p>
指針加1停巷, 指針的值遞增它所指向類型的大小(以字節(jié)為單位) 。
數(shù)組和指針的關(guān)系十分密切畔勤, 可以使用指針標(biāo)識數(shù)組的元素和獲得元素的值蕾各。 從本質(zhì)上看, 同一個對象有兩種表示法庆揪。C語言標(biāo)準(zhǔn)在描述數(shù)組表示法時確實借助了指針式曲。
days是數(shù)組首元素的地址, days + index是元素days[index]的地址缸榛, 而*(days + index)則是該元素的值吝羞, 相當(dāng)于days[index]。 for循環(huán)依次引用數(shù)組中的每個元素仔掸, 并打印各元素的內(nèi)容。
函數(shù)医清、數(shù)組和指針
total = sum(marbles); // 可能的函數(shù)調(diào)用
數(shù)組名是該數(shù)組首元素的地址起暮, 所以實際參數(shù)marbles是一個儲存int類型值的地址, 應(yīng)把它賦給一個指針形式參數(shù)会烙, 即該形參是一個指向int的指針
int sum(int * ar); // 對應(yīng)的函數(shù)原型
sum()獲得了該數(shù)組首元素的地址负懦, 知道要在該位置上找出一個整數(shù)。 注意柏腻, 該參數(shù)并未包含數(shù)組元素個數(shù)的信息纸厉。我們有兩種方法讓函數(shù)獲得這一信息。 第一種方法是五嫂, 在函數(shù)代碼中寫上固定的數(shù)組大小
指針表示數(shù)組名颗品, 也可以用數(shù)組名表示指針。 +=運(yùn)算符把右側(cè)運(yùn)算對象加到左側(cè)運(yùn)算對象上沃缘。
注意 聲明數(shù)組形參數(shù)組名是該數(shù)組首元素的地址躯枢, 作為實際參數(shù)的數(shù)組名要求形式參數(shù)是一個與之匹配的指針。
marbles是一個數(shù)組槐臀, ar是一個指向marbles數(shù)組首元素的指針锄蹂, 利用C中數(shù)組和指針的特殊關(guān)系, 可以用數(shù)組表示法來表示指針ar水慨。
使用指針形參
sum()函數(shù)使用一個指針形參標(biāo)識數(shù)組的開始得糜, 用一個整數(shù)形參表明待處理數(shù)組的元素個數(shù)(指針形參也表明了數(shù)組中的數(shù)據(jù)類型) 。 但是這并不是給函數(shù)傳遞必備信息的唯一方法晰洒。 還有一種方法是傳遞兩個指針朝抖, 第1個指針指明數(shù)組的開始處(與前面用法相同) , 第2個指針指明數(shù)組的結(jié)束處谍珊。
指針start開始指向marbles數(shù)組的首元素槽棍, 所以賦值表達(dá)式total += *start把首元素(20) 加給total。 然后, 表達(dá)式start++遞增指針變量start炼七, 使其指向數(shù)組的下一個元素缆巧。 因為start是指向int的指針, start遞增1相當(dāng)于其值遞增int類型的大小豌拙。
因為while循環(huán)的測試條件是一個不相等的關(guān)系陕悬, 所以循環(huán)最后處理的一個元素是end所指向位置的前一個元素。 這意味著end指向的位置實際上在數(shù)組最后一個元素的后面按傅。 C保證在給數(shù)組分配空間時捉超, 指向數(shù)組后面第一個位置的指針仍是有效的指針。
total += *start++;
一元運(yùn)算符*和++的優(yōu)先級相同唯绍, 但結(jié)合律是從右往左拼岳, 所以start++先求值, 然后才是*start况芒。 也就是說惜纸, 指針start先遞增后指向。 使用后綴形式(即start++而不是++start) 意味著先把指針指向位置上的值加到total上绝骚, 然后再遞增指針耐版。 如果使用*++start, 順序則反過來压汪, 先遞增指針粪牲, 再使用指針指向位置上的值。 如果使用(*start)++止剖, 則先使用start指向的值腺阳, 再遞增該值, 而不是遞增指針穿香。 這樣舌狗, 指針將一直指向同一個位置, 但是該位置上的值發(fā)生了變化扔水。
只有(*p3)++改變了數(shù)組元素的值痛侍, 其他兩個操作分別把p1和p2指向數(shù)組的下一個元素
指針表示法和數(shù)組表示法
處理數(shù)組的函數(shù)實際上用指針作為參數(shù), 但是在編寫這樣的函數(shù)時魔市, 可以選擇是使用數(shù)組表示法還是指針表示法主届。使用數(shù)組表示法, 讓函數(shù)是處理數(shù)組的這一意圖更加明顯待德。
C語言君丁, ar[i]和*(ar+1)這兩個表達(dá)式都是等價的。 無論ar是數(shù)組名還是指針變量将宪, 這兩個表達(dá)式都沒問題绘闷。 但是橡庞, 只有當(dāng)ar是指針變量時, 才能使用ar++這樣的表達(dá)式印蔗。
指針表示法(尤其與遞增運(yùn)算符一起使用時) 更接近機(jī)器語言扒最, 因此一些編譯器在編譯時能生成效率更高的代碼。