練習(xí)8:大小和數(shù)組
譯者:飛龍
在上一個練習(xí)中你做了一些算術(shù)運(yùn)算,不過帶有'\0'
(空)字符物遇。這對于其它語言來說非常奇怪,因為它們把“字符串”和“字節(jié)數(shù)組”看做不同的東西费薄。但是C中的字符串就是字節(jié)數(shù)組,并且只有不同的打印函數(shù)才知道它們的不同。
在我真正解釋其重要性之前赚爵,我先要介紹一些概念:sizeof
和數(shù)組。下面是我們將要討論的一段代碼:
#include <stdio.h>
int main(int argc, char *argv[])
{
int areas[] = {10, 12, 13, 14, 20};
char name[] = "Zed";
char full_name[] = {
'Z', 'e', 'd',
' ', 'A', '.', ' ',
'S', 'h', 'a', 'w', '\0'
};
// WARNING: On some systems you may have to change the
// %ld in this code to a %u since it will use unsigned ints
printf("The size of an int: %ld\n", sizeof(int));
printf("The size of areas (int[]): %ld\n",
sizeof(areas));
printf("The number of ints in areas: %ld\n",
sizeof(areas) / sizeof(int));
printf("The first area is %d, the 2nd %d.\n",
areas[0], areas[1]);
printf("The size of a char: %ld\n", sizeof(char));
printf("The size of name (char[]): %ld\n",
sizeof(name));
printf("The number of chars: %ld\n",
sizeof(name) / sizeof(char));
printf("The size of full_name (char[]): %ld\n",
sizeof(full_name));
printf("The number of chars: %ld\n",
sizeof(full_name) / sizeof(char));
printf("name=\"%s\" and full_name=\"%s\"\n",
name, full_name);
return 0;
}
這段代碼中我們創(chuàng)建了一些不同數(shù)據(jù)類型的數(shù)組宴霸。由于數(shù)組是C語言工作機(jī)制的核心囱晴,有大量的方法可以用來創(chuàng)建數(shù)組。我們暫且使用type name[] = {initializer};
語法瓢谢,之后我們會深入研究畸写。這個語法的意思是,“我想要那個類型的數(shù)組并且初始化為{..}”氓扛。C語言看到它時枯芬,會做這些事情:
- 查看它的類型,以第一個數(shù)組為例采郎,它是
int
千所。 - 查看
[]
,看到了沒有提供長度蒜埋。 - 查看初始化表達(dá)式
{10, 12, 13, 14, 20}
淫痰,并且了解你想在數(shù)組中存放這5個整數(shù)。 - 在電腦中開辟出一塊空間整份,可以依次存放這5個整數(shù)待错。
- 將數(shù)組命名為
areas
籽孙,也就是你想要的名字,并且在當(dāng)前位置給元素賦值火俄。
在areas
的例子中犯建,我們創(chuàng)建了一個含有5個整數(shù)的數(shù)組來存放那些數(shù)字。當(dāng)它看到char name[] = "Zed";
時瓜客,它會執(zhí)行相同的步驟适瓦。我們先假設(shè)它創(chuàng)建了一個含有3個字符的數(shù)組,并且把字符賦值給name
谱仪。我們創(chuàng)建的最后一個數(shù)組是full_name
,但是我們用了一個比較麻煩的語法疯攒,每次用一個字符將其拼寫出來揭芍。對C來說,name
和full_name
的方法都可以創(chuàng)建字符數(shù)組。
在文件的剩余部分呜舒,我們使用了sizeof
關(guān)鍵字來問C語言這些東西占多少個字節(jié)。C語言無非是內(nèi)存塊的大小和地址以及在上面執(zhí)行的操作笨奠。它向你提供了sizeof
便于你理解它們袭蝗,所以你在使用一個東西之前可以先詢問它占多少空間。
這是比較麻煩的地方般婆,所以我們先運(yùn)行它到腥,之后再解釋。
你會看到什么
$ make ex8
cc -Wall -g ex8.c -o ex8
$ ./ex8
The size of an int: 4
The size of areas (int[]): 20
The number of ints in areas: 5
The first area is 10, the 2nd 12.
The size of a char: 1
The size of name (char[]): 4
The number of chars: 4
The size of full_name (char[]): 12
The number of chars: 12
name="Zed" and full_name="Zed A. Shaw"
$
現(xiàn)在你可以看到這些不同printf
調(diào)用的輸出蔚袍,并且瞥見C語言是如何工作的乡范。你的輸出實際上可能會跟我的完全不同,因為你電腦上的整數(shù)大小可能會不一樣啤咽。下面我會過一遍我的輸出:
譯者注:16位機(jī)器上的
int
是16位的晋辆,不過現(xiàn)在16位機(jī)很少見了吧。
5
我的電腦認(rèn)為int
的大小是4個字節(jié)宇整。你的電腦上根據(jù)位數(shù)不同可能會使用不同的大小瓶佳。
6
areas
中含有5個整數(shù),所以我的電腦自然就需要20個字節(jié)來儲存它鳞青。
7
如果我們把areas
的大小與int
的大小相除霸饲,我們就會得到元素數(shù)量為5为朋。這也符合我們在初始化語句中所寫的東西。
8
接著我們訪問了數(shù)組贴彼,讀出areas[0]
和areas[1]
潜腻,這也意味著C語言的數(shù)組下標(biāo)是0開頭的,像Python和Ruby一樣器仗。
9~11
我們對name
數(shù)組執(zhí)行同樣的操作融涣,但是注意到數(shù)組的大小有些奇怪,它占4個字節(jié)精钮,但是我們用了三個字符來打出"Zed"威鹿。那么第四個字符是哪兒來的呢?
12~13
我們對full_name
數(shù)組執(zhí)行了相同的操作轨香,但它是正常的忽你。
13
最后我們打印出name
和full_name
,根據(jù)printf
證明它們實際上就是“字符串”臂容。
確保你理解了上面這些東西科雳,并且知道這些輸出對應(yīng)哪些創(chuàng)建的變量。后面我們會在它的基礎(chǔ)上探索更多關(guān)于數(shù)組和存儲空間的事情脓杉。
如何使它崩潰
使這個程序崩潰非常容易糟秘,只需要嘗試下面這些事情:
- 將
full_name
最后的'\0'
去掉,并重新運(yùn)行它球散,在valgrind
下再運(yùn)行一遍∧蜃現(xiàn)在將full_name
的定義從main
函數(shù)中移到它的上面,嘗試在Valgrind
下運(yùn)行它來看看是否能得到一些新的錯誤蕉堰。有些情況下凌净,你會足夠幸運(yùn),不會得到任何錯誤屋讶。 - 將
areas[0]
改為areas[10]
并打印冰寻,來看看Valgrind
會輸出什么。 - 嘗試上述操作的不同變式丑婿,也對
name
和full_name
執(zhí)行一遍性雄。
附加題
- 嘗試使用
areas[0] = 100;
以及相似的操作對areas
的元素賦值。 - 嘗試對
name
和full_name
的元素賦值羹奉。 - 嘗試將
areas
的一個元素賦值為name
中的字符秒旋。 - 上網(wǎng)搜索在不同的CPU上整數(shù)所占的不同大小。