C++ 學習筆記:深入理解 i++與 ++i

1 - 引言

還記得剛上大學學C++的時候,對於自增的操作,我的理解就是 ++ 符號在變量之前,就先對變量進行自增加 1 ,如果 ++ 位於變量之後,就在運算結束之後對變量加 1。

這種理解很淺顯, 但我感覺很實用,至少對一個初學者來說。比如猜測下面的輸出:

int i = 0;
printf("%d \n",++i); // 輸出爲1
i = 0printf("%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


正文結束,歡迎留言討論。

不得不說,自增的各種寫法真是反人類,使用的時候要謹慎,最好使用括號來明確輸出。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章