# 練習10:字符串數組和循環
> 原文:[Exercise 10: Arrays Of Strings, Looping](http://c.learncodethehardway.org/book/ex10.html)
> 譯者:[飛龍](https://github.com/wizardforcel)
你現在可以創建不同類型的數組,并且也知道了“字符串”和“字節數組”是相同的東西。接下來,我們要更進一步,創建一個包含字符串的數組。我也會介紹第一個循環結構,`for`循環來幫我們打印出這一新的數據結構。
這一章的有趣之處就是你的程序中已經有一個現成的字符串數組,`main`函數參數中的`char *argv[]`。下面這段代碼打印出了所有你傳入的命令行參數:
```c
include <stdio.h>
int main(int argc, char *argv[])
{
int i = 0;
// go through each string in argv
// why am I skipping argv[0]?
for(i = 1; i < argc; i++) {
printf("arg %d: %s\n", i, argv[i]);
}
// let's make our own array of strings
char *states[] = {
"California", "Oregon",
"Washington", "Texas"
};
int num_states = 4;
for(i = 0; i < num_states; i++) {
printf("state %d: %s\n", i, states[i]);
}
return 0;
}
```
`for`循環的格式是這樣的:
```c
for(INITIALIZER; TEST; INCREMENTER) {
CODE;
}
```
下面是`for`循環的工作機制:
+ `INITIALIZER`中是用來初始化循環的代碼,這個例子中它是`i = 0`。
+ 接下來會檢查`TEST`布爾表達式,如果為`false`(0)則跳過`CODE`,不做任何事情。
+ 執行`CODE`,做它要做的任何事情。
+ 在`CODE`執行之后會執行`INCREMENTER`部分,通常情況會增加一些東西,比如這個例子是`i++`。
+ 然后跳到第二步繼續執行,直到`TEST`為`false`(0)為止。
例子中的`for`循環使用`argc`和`argv`,遍歷了命令行參數,像這樣:
+ OS將每個命令行參數作為字符串傳入`argv`數組,程序名稱`./ex10`在下標為0的位置,剩余的參數緊隨其后。
+ OS將`argc`置為`argv`數組中參數的數量,所以你可以遍歷它們而不會越界。要記住如果你提供了一個參數,程序名稱是第一個,參數應該在第二個。
+ 接下來程序使用`i < argc`測試`i`是否使用`argc`,由于最開始`1 < 2`,測試通過。
+ 之后它會執行代碼,輸出`i`,并且將`i`用做`argv`的下標。
+ 然后使用`i++`來運行自增語句,它是`i = i + 1`的便捷形式。
+ 程序一直重復上面的步驟,直到`i < argc`值為`false`(0),這時退出循環但程序仍然繼續執行。
## 你會看到什么
你需要用兩種方法運行它來玩轉這個程序。第一種方法是向命令行參數傳遞一些東西來設置`argc`和`argv`。第二種是不傳入任何參數,于是你可以看到第一次的`for`循環沒有被執行,由于`i < argc`值為`false`。
## 理解字符串數組
你應該可以從這個練習中弄明白,你在C語言中通過混合`char *str = "blah"`和`char str[] = {'b','l','a','h'}`語法構建二維數組來構建字符串數組。第十四行的`char *states[] = {...}`語法就是這樣的二維混合結構,其中每個字符串都是數組的一個元素,字符串的每個字符又是字符串的一個元素。
感到困惑嗎?多維的概念是很多人從來都不會去想的,所以你應該在紙上構建這一字符串數組:
+ 在紙的左邊為每個字符串畫一個小方格,帶有它們的下標。
+ 然后在方格上方寫上每個字符的下標。
+ 接著將字符串中的字符填充到方格內。
+ 畫完之后,在紙上模擬代碼的執行過程。
理解它的另一種方法是在你熟悉的語言,比如Python或Ruby中構建相同的結構。
## 如何使它崩潰
+ 使用你喜歡的另一種語言,來寫這個程序。傳入盡可能多的命令行參數,看看是否能通過傳入過多參數使其崩潰。
+ 將`i`初始化為0看看會發生什么。是否也需要改動`argc`,不改動的話它能正常工作嗎?為什么下標從0開始可以正常工作?
+ 將`num_states`改為錯誤的值使它變大,來看看會發生什么。
## 附加題
+ 弄清楚在`for`循環的每一部分你都可以放置什么樣的代碼。
+ 查詢如何使用`','`(逗號)字符來在`for`循環的每一部分中,`';'`(分號)之間分隔多條語句。
+ 查詢`NULL`是什么東西,嘗試將它用做`states`的一個元素,看看它會打印出什么。
+ 看看你是否能在打印之前將`states`的一個元素賦值給`argv`中的元素,再試試相反的操作。
- 笨辦法學C 中文版
- 前言
- 導言:C的笛卡爾之夢
- 練習0:準備
- 練習1:啟用編譯器
- 練習2:用Make來代替Python
- 練習3:格式化輸出
- 練習4:Valgrind 介紹
- 練習5:一個C程序的結構
- 練習6:變量類型
- 練習7:更多變量和一些算術
- 練習8:大小和數組
- 練習9:數組和字符串
- 練習10:字符串數組和循環
- 練習11:While循環和布爾表達式
- 練習12:If,Else If,Else
- 練習13:Switch語句
- 練習14:編寫并使用函數
- 練習15:指針,可怕的指針
- 練習16:結構體和指向它們的指針
- 練習17:堆和棧的內存分配
- 練習18:函數指針
- 練習19:一個簡單的對象系統
- 練習20:Zed的強大的調試宏
- 練習21:高級數據類型和控制結構
- 練習22:棧、作用域和全局
- 練習23:認識達夫設備
- 練習24:輸入輸出和文件
- 練習25:變參函數
- 練習26:編寫第一個真正的程序
- 練習27:創造性和防御性編程
- 練習28:Makefile 進階
- 練習29:庫和鏈接
- 練習30:自動化測試
- 練習31:代碼調試
- 練習32:雙向鏈表
- 練習33:鏈表算法
- 練習34:動態數組
- 練習35:排序和搜索
- 練習36:更安全的字符串
- 練習37:哈希表
- 練習38:哈希算法
- 練習39:字符串算法
- 練習40:二叉搜索樹
- 練習41:將 Cachegrind 和 Callgrind 用于性能調優
- 練習42:棧和隊列
- 練習43:一個簡單的統計引擎
- 練習44:環形緩沖區
- 練習45:一個簡單的TCP/IP客戶端
- 練習46:三叉搜索樹
- 練習47:一個快速的URL路由
- 后記:“解構 K&R C” 已死