這道題你們可能會讓你們有點暈,至少我是的,由於咱們平時都是buf+1這種寫法,若是你是第一次接觸這種寫法的話,其實你們只要把數組考慮成普通變量就好了,給你們舉個例子 java
int a = 0; linux
int *p = &a+1; windows
這裏的&a你們是否是感受很正常,就是這樣,那麼如今咱們反過來,&buf就是取數組的地址, 數組
你們都知道&a+1 是表明a的地址加上四個字節,那是由於a是int型的,佔四個字節,因此加上4個字節,那麼&buf地址再加1就是加上buf變量的大小,buf是10個char元素數組,因此&buf + 1就至關於buf的地址加上10*1(char型的大小) 數據結構
上面 只是幫助你理解,若是純粹從代碼的角度來講, 函數
&buf的地址類型爲 char (*p)[10] 至關於行指針的類型 ,那麼p+1就至關於p的地址加上10*1個字節。 3d
int a=3,b;
b=++a+(++a)+(++a);
printf("%d",b); 指針
這道題在windows下與linux下的結果不一樣,可是我我的支持linux下gcc編譯的結果16,windows下爲18,編譯器的不一樣,解釋就不一樣, blog
下面解析一下linux下爲何爲16?get
不知道你們數據結構課的時候有沒有寫過表達式計算,其中有一種實現就是用兩個棧來表示,一個棧用來表示運算符,另外一個表示操做數。b = ++a + (++a) + (++a)
首先++入棧 以下圖(編譯器是從左往右一個個字符讀取的 因此a先入棧)
而後a入棧
這時候會繼續日後面讀取 發現是一個+號,由於加號優先級比++小,因此先執行++a
這時候會把++彈出棧,a彈出棧,再把++a的結果壓棧,+號壓棧,
這裏必定要注意是把++a的結果雖然是4可是因爲++a返回的是引用,因此壓棧放的是a這個變量,而不是4
而後繼續執行後面的(++a),這裏是同樣的,我就不詳解釋,當把第一個(這裏的第一個值得是第一個帶括號的++a)(++a)運算完畢以後,會繼續讀取後面的+號,這時候發現棧裏面已經有了一個加號,優先級同樣,按照c語言運算符+號的運算方向,從左往右,因此先運算棧裏面的加號此時棧裏面的狀況以下圖:
這時候執行了兩次++a,a的值已經變爲5了,因此這時候兩個a相加等於10,這時候運算結束以後,將10壓入棧,(注意這裏壓棧的就是10不像以前壓棧的是a這個變量)
結束以後棧以下
後面再次執行++a 一樣先計算++a,再將a的值壓入棧中,在執行加法:
a的值變爲6了 因此最後結果爲16.
下面這幅圖是windows下的結果,編譯器的不一樣。
上面這個題目須要咱們用到彙編語言棧幀的問題,在彙編中若是咱們調用另外一個函數,會使用call命令,call所作的事情第一個將下一條命令的地址壓棧,而後jmp到調用函數的地址,這裏還會設置,esp與ebp的知識,我在這知識提一下,由於棧幀的知識不是一兩句能說清楚的,函數的第一句都會
push ebp;這句是爲了保護調用函數的棧幀,
ebp地址上面是局部變量,
因此(int*)(*(&p+1));獲得就是保護的上一個函數的ebp棧幀。
p-=1;獲得就是a的地址
*p = 520;這樣就能夠改變a的內容了。
可是這個能不能運行成功跟gcc版本有關係。gcc4.8能運行而且能修改。
java中實例代碼初始化塊{}與直接在聲明的時候初始化的優先級?
答案是同樣,那個在前面那個就先執行
int a[][3] = {1, 2, 3, 4, 5, 6};
int (*ptr)[3] = a;
printf("%d %d ", (*ptr)[1], (*ptr)[2]);
++ptr;
printf("%d %d\n", (*ptr)[1], (*ptr)[2]);
下面的能編譯嗎?gcc的版本不同形成不一樣結果,gcc5.幾版本 編譯不經過
這裏涉及前加加與後加加哪一個返回引用的問題,以及貪心詞法(C語言缺陷與陷阱)
我記錄一下個人見解,a++返回臨時變量 這時候不能再對這個臨時變量進行後加加,由於它不是左值
int a = 1;
int b = 2;
int c = a+++++b;