++是C++的自增運算符,作用是使變量自加1;--是自減運算符,作用是使變量自減1。++和--有兩種用法,一種是前綴用法,一種是後綴用法。前綴用法如:++i、--i ,後綴用法如i++、i--,前綴用法跟後綴用法的差別在於前綴時++i的值為完成i加1後的值,--i為完成i減1後的值。例如:假設i的初值為3,執行cout<<++i<<endl;輸出結果為4,而執行cout<<i++<<endl;輸出結果為3。--運算符同理。這是世人皆知的常識,我們不再討論,現在我們來討論一點有趣的東西,看如下代碼:
#include <iostream>
using namespace std;
int main()
{
int i=3;
cout<<(i++)+(i++)+(i++)<<endl;
cout<<i<<endl;
return 0;
}
問,第一次和第二次輸出的結果分別是多少?
有人說,是12和6。理由是,表達式從左至右開始計算,因為第一個括號內++運算符是後綴用法,i的初值為3,所以,第一個括號的值是3,計算完第一個括號之後,i自加1,變成4,然後計算第二個括號,第二個括號裡的++也是後綴用法,所以,值為4,執行完第二個括號後,i再加1,變成5,接下計算第三個括號,第三個括號裡的++也是後綴用法,所以,第三個括號的值為5,然後計算第三個括號相加的和,即3+4+5=12。這個理由看起來不錯,似乎應當是這樣。然而,運行結果卻讓人大跌眼鏡,竟然是9和6。這是怎麼回事呢?說起來也很簡單,這是因為很多編譯系統規定,在遇到一條計算表達式中同時出現若干i++、i--的情況時,在當前語句中並不執行i的自增和自減,i的初值是多少,i++和i--的值就是多少,當這條表達式執行完成之後,再將i連續自加或自減若干次。
再看如下代碼:
#include <iostream>
using namespace std;
int main()
{
int i=3;
cout<<(++i)+(++i)+(++i)<<endl;
cout<<i<<endl;
return 0;
}
問,第一次和第二次輸出的結果分別是多少?
有人說,結果應該是4+5+6=15和6。理由我想大家都想明白,我就不多說了。還有人總結了上例的經驗,認為,輸出結果應該是9和6。我們來運行一下這個程序,看看誰說得對……
好了,運行結果出來了,不過這不是什麼好結果,可能很多人看完會抓狂,結果盡然是神鬼莫測的18和6。為什麼呢?道理跟上例差不多,那就是很編譯系統規定,連續多個前綴式++和--運算符出現在同一個運算表達式中時,先將變量連續自加或自減N次,然後判定++i的值為i+N。
為了驗證上面的說法,請看下面的代碼:
#include <iostream>
using namespace std;
int main()
{
int i=3;
cout<<(++i)+(i++)+(++i)<<endl;
cout<<i<<endl;
return 0;
}
按照我們上面的推測,第一個輸出語句應當是這樣執行的:首先,掃描整條運算表達式(++i)+(i++)+(++i),發現有兩處++的前綴式用法,於是,將i連續自加兩次,然後開始計算表達式,第一個括號是++i,判定為5,第二個括號是i++,判定值為5,第三個括號是++i判定值為5,最後,計算結果5+5+5=15。因為表達式中有一個i++,所以執行計算完之後將i的值再自加1,變為6。
運行程序,驗證一下,果然,結果就是15和6。
下面在來討論一下網上很多C++論壇裡討論得很多的int i=3;問++i+++i+i++的值是多少的問題。
我看到CSDN裡也有人在討論這個問題,很多人在回帖,答案似乎多種多樣,有說是12的,有說是18的,更有說是9的,更有一條回帖十分搞笑——“答案是×××,這是很早以前我的一個很牛×的老師教我的解法得出的結果”。我很無語。學過編譯原理的人都知道,“++i+++i”這一段根本就無法解析,編譯系統從左至右掃描整條語句,先遇到++i,判斷出來是一個i的前綴自加運算,然後接著掃描,遇到一個+,+是一個二目運算符,它的左邊已經有一個運算數++i了,系統就向右搜索第二個運算數,又遇到一個+,++比+的運算級別要高,這時,編譯系統就將兩個+看成一個整體來處理,既然是++,編譯系統就認定,肯定它的左邊或右邊有一個變量,編譯系統先搜索左邊,發現有一個 i,是個變量,於是它就將i和其後的++組合起來,這時問題就發生了,也就是說第一個i被編譯系統綁架到它後面的++那裡去了,那麼i前面的++是個什麼東西呢?編譯系統是無法搞明白的,它會倒回去重新搜索++前面是否有左值,發現沒有,因此它就認為++是一個缺少左值的自增運算符,於是提示提示用戶:'++' needs l-value
我們寫個程序驗證一下上面的推測:
#include <iostream>
using namespace std;
int main()
{
int i=3;
cout<<++i+++i+i++<<i<<endl;
cout<<i<<endl;
return 0;
}
果然,編譯時有一個錯誤,提示error C2105: '++' needs l-value ,證實了我們的推測。這個問題的討論使我們得出一個結論:如果一個變量Ni的兩側都有++或--運算符並且Ni左邊的表達式不能分解成X+或X-的形式,那麼編譯就會出錯,X是有值變量。結論有點繞口,舉例說明吧:
程序1
#include <iostream>
using namespace std;
int main()
{
int i=3;
cout<<i+++i++<<endl;
cout<<i<<endl;
return 0;
}
程序1說明:表達式i+++i++中第二個i的左右兩側都有++,於是我們看第二個i的左側,左側是i+++,可以分解為(i++)+,其中“(i++)”是有值變量,符合X+的形式,因此i+++i++是合法表達式,可以通過編譯。
程序2
#include <iostream>
using namespace std;
int main()
{
int i=3;
cout<<++i+++i<<endl;
cout<<i<<endl;
return 0;
}
程序2說明:表達式++i+++i中第一個i的左右兩側都有++,於是我們看第一個i的左側,左側是++,不能分解成X+的形式,因此該表達式不合法。編譯時會提示:error C2105: '++' needs l-value
下面,我們再來討論一下關於i+++i的問題。曾經有人問,表達式i+++i在編譯時,編譯系統是怎麼拆分的?究竟是拆分成(i++)+i呢,還是拆分成i+(++i)。
這個問題本身的答案很簡單,是(i++)+i,不明白的自己去看編譯原理。這個問題令人感興趣之處並不在這裡,不知道大家注意到i+(++i)這個表達式有什麼奇特的地方沒有?假設有如下程序:
#include <iostream>
using namespace std;
int main()
{
int i=3;
cout<<i+(++i)<<endl;
cout<<i<<endl;
return 0;
}
大家可以猜測一下程序的運行結果。
很多人可能會說是7和4,看起來的確像這樣。但是,非常遺憾,實驗再一次證明,你可能猜錯了,結果是8和4。為什麼是8和4呢?前面說過int i=3;cout<< (++i)+(++i) <<endl;的情況,編譯系統會先將i連續自加1兩次,然後將(++i)一律判定為5進行結算,輸出10。這裡同理,編譯系統現將i自加1,然後再對i+(++i)做運算,(++i)的值判定為4,i的值也判定為4,因此計算結果是8。
下面我們來討論int i=3;cout<<i++<<” and ”<<i++<<endl;的問題。首先請看如下程序,猜測輸出結果:
#include <iostream>
using namespace std;
int main()
{
int i=3;
cout<<i++<<" and "<<i++<<endl;
cout<<i<<endl;
return 0;
}
很多人認為輸出結果應該是“3 and 4”和5。我們把代碼復制到VC6.0或VC2005上編譯運行一下,看看結果……
好了,運行結束,結果是“4 and 3”和5。Oh!My God!Can you tell me why?上帝不會告訴你,我可以告訴你。這是因為很多編譯系統在處理輸出流時,是從右至左的。在上面的例子中,兩處i++處於同一個輸出序列中,編譯系統會先計算處於右側的第二個i++,這時i的值為3,因此右側i++的值為3,之後,i+1變成4,計算第一個i++的值為4,計算完之後將i的值再加1,最後才是輸出結果,所以輸出結果是4和3。