1 - 引言
還記得剛上大學學C++的時候,對於自增的操作,我的理解就是 ++ 符號在變量之前,就先對變量進行自增加 1 ,如果 ++ 位於變量之後,就在運算結束之後對變量加 1。
這種理解很淺顯, 但我感覺很實用,至少對一個初學者來說。比如猜測下面的輸出:
int i = 0;
printf("%d \n",++i); // 輸出爲1
i = 0;
printf("%d \n",i++); // 輸出爲0
似乎和我想的一樣,結果就是這麼個結果。可實際上和我的理解相差甚遠,很遺憾此時的我還沒有發現到問題。
直到有一天,我遇到了下面這些語句,我的頭腦似乎已經不夠用了(這是怎麼肥事?怎麼會有這種反人類的句子?)
a+=(a++);
a+=(++a);
(++a)+=(a++);
(++a)+=(++a);
(a++)+=(++a); // 編譯不通過a++不能作爲左值
a = a+++a;
題目抽象得一匹,該從哪一部分開始運算?是先算 ++a 還是先算 a++?先算左邊還是先算右邊?爲什麼 ++a 可以作爲左值而 a++ 不可以?
如果大神路過就請忽視我,下面開始垃圾程序員的惡補!!!
2 - 自增的實現
下面是從網上搜來的一段C/C++實現。(我爲什麼不寫?這不很明顯嗎?太辣雞了~)
/* ++i的實現 */
int& operator++(){
*this += 1;
return *this;
}
/* i++的實現 */
int operator++(int) { // int有點迷啊!?
int temp = *this;
++*this; // 直接用++有點小秀
return temp;
}
看起來彆扭沒關係,還有一篇,從牛客網(nowcoder)的一個回覆借來的。(來自讀書人的吐槽)
/* ++i的實現 */
int& pre_increment(int &a){
a = a + 1;
return a;
}
/* i++的實現 */
int post_increment(int &a){
int temp = a;
a = a + 1;
return temp;
}
留意兩篇C/C++代碼中函數的返回值,++i 返回的是引用,而 i++ 返回的是臨時變量的值。
返回一個引用和一個值有什麼區別?
學習引用(reference)的時候,我們應該會了解到,流運算符(<<和>>)重載選擇將引用作爲返回值的一個原因是支持連續操作,如cout << a << b << c
。爲什麼?因爲它可以繼續在返回值上操作。但當返回的是一個值的時候,我們只能捕獲這個值,卻不能修改它,如a = get()
,但不能get() = a
。
看到這裏,實際上我已經解決了一個問題,在C/C++中爲什麼 ++i 可以作爲一個左值放在等號(=)的左邊?
是因爲 ++i 實際上進行自增操作之後,返回的是一個引用,這個引用是確定的,就是我們重載運算符傳進去的實參,是一個在內存分配地址的變量,如代碼中的a,它是可以修改的。相對應的,i++返回的只是一個值,這個值只能輸出或者賦給一個變量,但他不能修改,所以它不是一個左值。
爲什麼我會將第二篇代碼借過來?是因爲第二篇簡單一點嗎?(有這個原因…但不是主要的)
第二篇代碼將 ++ 的過程抽取成一個函數,他告訴我將 ++ 操作看作函數調用的過程,而不再是看做是先增還是後增的問題。說的有點抽象,下面舉個例子:
int a = 0;
int b = 0;
b = a++;
printf(" b = %d \n", b);
輸出會是什麼呢?
輸出 b = 0,先賦值再自增,好理解。
如果是下面的代碼呢?
int a = 0;
int b = 0;
b = (a++) + (a++) + (a++);
printf(" b = %d \n", b);
printf(" a = %d \n", a);
輸出 b = 3,a = 3,好像有點東西哦~~~
爲什麼 b = 3 ?
因爲 b = 0 + 1 + 2 = 3. 將每一次 ++ 操作看做是一次函數調用,b = incv(a) + incv(a) + incv(a),這樣是不是好理解很多。第一次自增返回值爲0,但 a = 1,第二次自增返回值爲 1,a = 2,第三次自增返回值爲 2,a = 3。
再換一個寫法:
int a = 0;
int b = 0;
b = (++a) + (a++) + (a++);
printf(" b = %d \n", b);
printf(" a = %d \n", a);
輸出b=4,a=3。其中,b = 1 + 1 + 2.
最後一個例子:
int a = 0;
int b = 1;
b = a +++ b;
printf(" b = %d \n", b);
printf(" a = %d \n", a);
輸出 b = 1, a = 1 。顯然,這個結果是因爲 a +++ b
等同於 (a ++)+ b
。
3 - 其他語言中的自增符號
其他語言,我暫時還沒有深入瞭解,以後有機會再補充。嘗試過將 Java語言的++i 作爲左值,但是編譯沒有通過。
4 - 參考
https://blog.csdn.net/u014465639/article/details/72812187
https://www.nowcoder.com/questionTerminal/f38ddc9c23e1453fb56fa80e26225e9f
正文結束,歡迎留言討論。
不得不說,自增的各種寫法真是反人類,使用的時候要謹慎,最好使用括號來明確輸出。