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