第5章-循環和關係表達式
主要知識點:遞增/遞減運算符。
5.1 for循環
cout.setf(ios_base::boolalpha)
:通常,cout在顯示bool值之前都會轉換成int,此函數設置了一個標記,命令cout顯示true或false,而非1或0。
遞增/遞減運算符
分爲前綴(prefix)++i
,後綴(postfix)i++
。
- 前綴函數:先加後用。將值
i
加1,然後把i+1
賦給i
; - 後綴函數:先用再加。把
i
複製一個副本,將副本的值加1,然後把副本的值i+1
賦給i
。
從上面也可以看出,前綴的速度要比後綴高。後綴是比較難理解的,我們結合例子去解釋:
int a = 20;
int b = 20;
cout << a << " " << b << endl; // 20 20
cout << a++ << " " << ++b << endl; // 20 21
cout << a << " " << b << endl; //21 21
第4行其實可以先int c = a++;
,便可以寫成cout << c ...
,也就是輸出的是c的值,那麼爲什麼c是20而不是21呢?
首先從運算的優先級上講,遞增運算高於賦值操作,所以a先複製一個副本並+1,但是什麼時候把這個副本值賦給a呢?執行完順序點!接下來引入副作用和順序點。
- 副作用(side effect):計算表達式時對某些東西,比如存在變量中的值進行了修改;
- 順序點(sequence point):程序執行過程中的一個點,在進入下一步之前要確保對所有的副作用進行了評估。C++中,分號就是一個順序點,意味着程序處理下一條語句前,賦值運算符和遞增/遞減運算符的所有修改必須完成。
所以對於int c = a++;
來說,後綴操作只能執行到副本+1這一步,之後就要執行把值a賦給c這步,而此時a的值仍是20,所以c的值也是20。
程序在執行完第4行後,要對所有的副作用進行評估,便會把副本+1的結果賦給a,執行完第4行後,a的值更新爲了21。也就是說:順序點執行完成後,後綴運算纔會把副本+1的值賦給本身。
++b
就沒有上面那麼麻煩了,執行完後就會直接更新b的值。
對於for循環的自增操作,比如for(int i=0; i<10; i++)
,我們可以看到括號裏是用的分號隔開,這意味着每個表達式的末尾是個順序點,所以執行完i++
後,就完成了把副本+1的值賦給i的這個過程。
遞增/遞減和while循環
int guests = 0;
while(guests++ < 10)
cout << guests << endl;
// output: 1,2,3...9,10
首先guests++ < 10
的末尾是個順序點,當guests=0
是,執行完這個順序點guests=1
,傳給下面的cout打印;直到guests=9
,執行完順序點後guests=10
,此時便不符合guests++ < 10
這個條件了,程序結束。
遞增/遞減和指針
這裏主要涉及優先級問題,
- 前綴遞增/遞減和
*
運算符的優先級相同,故整體上從右向左結合; - 後綴遞增/遞減優先級高於前綴,自然也高於
*
。
設pt->arr[0]
,可以總結如下:
常見類型 | 解釋 |
---|---|
*++pt; |
先運算++pt ,則pt->arr[1] ,然後取arr[1] 的值 |
++*pt; |
先取*pt 即arr[0] 的值,然後++arr[0] |
(*pt)++; |
括號優先級最高,所以先取*pt 即arr[0] 的值,然後arr[0]++ |
*pt++; |
先執行pt++ ,結合上文此時pt->arr[0] ,然後取arr[0] 的值,這句執行完後(順序點)纔有pt->arr[1] |
語句塊和變量
如果在一個語句塊內聲明一個變量,而外部語句塊中也有一個這種變量,如下面所示:
int x = 10;
{
cout << x << endl; // 10
int x = 100;
cout << x << endl; // 100
}
cout << x << endl; // 10
從第4行聲明新變量開始,到這個語句塊結束,新變量將隱藏舊變量。結束後該變量再次可見。
逗號運算符和字符串翻轉
#include <iostream>
int main() {
using namespace std;
cout << "Enter a word: " << endl;
string word;
cin >> word;
char temp;
int i, j;
for (j=0, i=word.size()-1; j<i; --i, ++j) {
temp = word[i];
word[i] = word[j];
word[j] = temp;
}
cout << word << "\nDone!";
return 0;
}
執行效果:輸入stressed
,輸出desserts
。這個代碼在string類有更好的實現方式,但現階段可以先參考這個使用。
第10行中使用逗號同時操作i
和j
,這是逗號運算符。允許把兩條或更多語句放在C++語法只允許放一個表達式的地方。第10行的本質是把這兩個合成爲1個。
也可以這樣寫int j=0, i=word.size()-1;
也能取得同樣的效果,但這裏的,
就是列表分隔符,而不是逗號運算符。同樣的還有第9行中,int i, j
同時初始化i
和j
,也是分隔列表中的變量。
逗號運算符有如下三個特點:
- 逗號運算符是個順序點。先確保第一個表達式,然後計算第二個表達式。
i=20, j=2*i
則有i=20, j=40
; - 逗號表達式的值是第二部分。比如上面的表達式的值就是40,轉換成bool類型爲true;
- 逗號運算符的優先級是最低的。
(cat=70), 240
執行括號中的表達式,240沒什麼作用。
cat=(70, 240)
:這個表達式結合上面的第二點,cat=240
。
關係運算符
x+3 < y-2
等價於(x+3) < (y-2)
。這是因爲關係運算符的優先級低於算術運算符。