c語言中指針指向的非指針變數不能使用++或--嗎?

int *p = (int*)malloc(sizeof(int));
*p = 5;
//*p++;
*p += 1;
printf("%d
", *p);
我用*p++;發現結果是垃圾值,而用*p += 1;或 *p = *p + 1;還有 ++*p;就不會出現問題,這是什麼原因造成的?


因為 postfix increment 的優先順序較 deference 高,所以 *p++ 等同於 *(p++)。運算符 = 和 += 的優先順序都較 deference 低。如果你是想把 deference 後的值加一,可用 (*p)++。

可以參考 C Operator Precedence。


個人建議在你哪怕有那麼一點點不sure的時候,堅定的使用括弧。因為:1,正常人都不會嘲笑打很多括弧的人;2,由於優先順序導致的問題可能延後爆發甚至side effect到別處爆發,到時你有那debug的工夫,都夠打一千個括弧的了;3,當你對某處的優先順序不很sure的時候,很可能別人在那裡也會有點含糊。你打了括弧節約了將來讀你代碼的人的一分鐘生命。4,我甚至有的時候會刻意把大長算式拆開寫只為提高可讀性。其實這樣做偶爾更方便編譯器優化。

括弧!

(*p)++,最後就是你預期的7了。


少個括弧吧,優先順序問題


因為你用*p++時把++作用到p上了,所以本來要續給*p的1s續給了p.逃~


學術概念上不太正確(關於 unary 的定義)但實際上是對的解釋:C語言中,所有 unary operator 單目運算符,優先順序都是有著 left to right associativity 的比 right to left 的高,即放在被操作量右邊的先算。

例如:

*p++ 先算右邊的 suffix increment,再做 dereference。要反過來的話應該用 (*p)++ 表示 p 指向的內容自加。

char *foo() 先看右邊的圓括弧(這並不是 unary op 了),foo 是一個函數,返回指向 char 的指針。如果要定義指向函數的指針,應該是 char (*foo)()。


知乎整天這種低級語法問題問個沒完。這種調試的時候跟進去看變數一目了然還印象深刻。


1. int *p = (int*)malloc(sizeof(int));

假設這句代碼分配給指針p的值是0x123;
2. *p = 5;

地址是0x123的地方存了一個值是5;
3. *p++;

編譯器先計算p++,此時指針p的值就是0x123+1=0x124,再計算*p,取出地址是0x124存的東西,至於地址0x124存的什麼東西,只有上帝才知道。
4. 用*p += 1;編譯器會展開為*p = *p + 1;也就是*p = 5 +1,當然輸出正常值;

5. 用++*p;編譯器會先計算*p,為5,再計算++,也就是5 + 1 = 6.

總結一下,就是*運算符,和++運算符,哪個先執行的問題!


一元運算符*和++是有相等的優先順序,但結合的時候是從右向左的。++是用在了p上,也就是指針+1,而不是用在了*p上(也就是通過說的指針所指向的數據自加1)。


曾經。我對優先順序倒背如流。搞得編譯參數都得加個 -Wno-parentheses 。直到後來,我險些玩脫了。


這代碼感覺像譚浩強的風格啊……


推薦閱讀:

指針是如何記住步長的?
C中有沒有將一個函數轉變為另一個函數的函數(例如求導運算)?
函數實現的時候,將函數返回值另起一行書寫,這是一種好的代碼書寫風格么?
C語言中volatile修飾符的作用?
學習 C/C++ ,有什麼書籍推薦?

TAG:編程 | C編程語言 | 編譯原理 | CC | 指針 |