前兩節我們在while
和do/while
循環中使用循環變數,其實使用循環變數最見的是for
循環這種形式。for
語句的語法是:
for (控製表達式1; 控製表達式2; 控製表達式3) 語句
如果不考慮循環體中包含continue
語句的情況(稍後介紹continue
語句),這個for
循環等價于下面的while
循環:
控製表達式1; while (控製表達式2) { 語句 控製表達式3; }
從這種等價形式來看,控製表達式1和3都可以為空,但控製表達式2是必不可少的,例如for (;1;) {...}
等價于while (1) {...}
死循環。C語言規定,如果控製表達式2為空,則認為控製表達式2的值為真,因此死循環也可以寫成for (;;) {...}
。
上一節do/while
循環的例子可以改寫成for
循環:
int factorial(int n) { int result = 1; int i; for(i = 1; i <= n; ++i) result = result * i; return result; }
其中++i
這個表達式相當於i = i + 1
[9],++稱為首碼自增運算符(Prefix Increment Operator),類似地,--稱為首碼自減運算符(Prefix Decrement Operator)[10],--i
相當於i = i - 1
。如果把++i
這個表達式看作一個函數調用,除了傳入一個參數返回一個值(等於參數值加1)之外,還產生一個Side Effect,就是把變數i
的值增加了1。
++
和--
運算符也可以用在變數後面,例如i++
和i--
,為了和首碼運算符區別,這兩個運算符稱為尾碼自增運算符(Postfix Increment Operator)和尾碼自減運算符(Postfix Decrement Operator)。如果把i++
這個表達式看作一個函數調用,傳入一個參數返回一個值,返回值就等於參數值(而不是參數值加1),此外也產生一個Side Effect,就是把變數i
的值增加了1,它和++i
的區別就在於返回值不同。同理,--i
返回減1之後的值,而i--
返回減1之前的值,但這兩個表達式都產生同樣的Side Effect,就是把變數i
的值減了1。
使用++、--運算符會使程序更加簡潔,但也會影響程序的可讀性,[K&R]中的示例代碼大量運用++、--和其它表達式的組合使得代碼非常簡潔。為了讓初學者循序漸進,在接下來的幾章中++、--運算符總是單獨組成一個表達式而不跟其它表達式組合,從第 11 章 排序與查找開始將採用[K&R]的簡潔風格。
我們看一個有意思的問題:a+++++b
這個表達式如何理解?應該理解成a++ ++ +b
還是a++ + ++b
,還是a + ++ ++b
呢?應該按第一種方式理解。編譯的過程分為詞法解析和語法解析兩個階段,在詞法解析階段,編譯器總是從前到後找最長的合法Token。把這個表達式從前到後解析,變數名a
是一個Token,a
後面有兩個以上的+號,在C語言中一個+號是合法的Token(可以是加法運算符或正號),兩個+號也是合法的Token(可以是自增運算符),根據最長匹配原則,編譯器絶不會止步于一個+號,而一定會把兩個+號當作一個Token。再往後解析仍然有兩個以上的+號,所以又是一個++運算符。再往後解析只剩一個+號了,是加法運算符。再往後解析是變數名b
。詞法解析之後進入下一階段語法解析,a
是一個表達式,表達式++還是表達式,表達式再++還是表達式,表達式再+b還是表達式,語法上沒有問題。最後編譯器會做一些基本的語義分析,這時就有問題了,++運算符要求操作數能做左值,a
能做左值所以a++
沒問題,但表達式a++
的值只能做右值,不能再++了,所以最終編譯器會報錯。
C99規定了一種新的for
循環語法,在控製表達式1的位置可以有變數定義。例如上例的循環變數i
可以只在for
循環中定義:
int factorial(int n) { int result = 1; for(int i = 1; i <= n; i++) result = result * i; return result; }
如果這樣定義,那麼變數i
只是for
循環中的局部變數而不是整個函數的局部變數,相當於第 1 節 “if語句”講過的語句塊中的局部變數,在循環結束後就不能再使用i
這個變數了。這個程序用gcc
編譯要加上選項-std=c99
。這種語法也是從C++借鑒的,考慮到兼容性不建議使用這種寫法。
[9] 這兩種寫法在語義上稍有區別,詳見第 2.1 節 “復合賦值運算符”。
[10] increment和decrement這兩個詞很有意思,大多數字典都說它們是名詞,但經常被當成動詞用,在計算機術語中,它們當動詞用應該理解為increase by one和decrease by one。現代英語中很多原本是名詞的都被當成動詞用,字典都跟不上時代了,再比如transition也是如此。