請看我寫的如下代碼:

#include&

int main()
{
int value = 1;
int* ptr = value; // *ptr = value
printf("%d
", value); //輸出值 |
printf("%d
", *ptr); //輸出值 |
printf("%p
", value); //輸出地址 |
printf("%p
", ptr); //輸出地址 |
printf("%d
", *ptr == value); //ture *ptr == value
printf("%d
", ptr == value); //true
/*

*/
return 0;
}

從輸出的情況可以看出ptr是value的地址也即value,而*ptr代表value的值。即ptr == value,而*ptr == value。

可是在賦值的時候是*ptr = value,那麼*ptr應該與value等價才對,可在使用時兩者並不等價(見上)。這種賦值語句的寫法雖然不影響我正常地使用指針編寫程序,但對於我這種有強迫症的人來說這種賦值語法顯得很擰巴,並且有一定的誤導性。

所以從底層實現上來說這段代碼是怎樣被編譯的呢?指針是*ptr還是ptr呢?謝謝!


嗯哼,你問到了指針這個東西,最容易迷惑人的一個地方。

int* ptr = value;

這一行是聲明的語法,是規定出來的,即聲明ptr是一個指針,同時ptr= value

這跟平時使用這個指針的時候,賦值 *ptr = value 不是一回事。

所以你才會有這個疑問。說穿了不值一提。

你其他理解都是對的


在題主的代碼中可以看到int* ptr、value、value、*ptr、ptr、 *ptr == value)、ptr == value等寫法,是不是看上去眼花繚亂、傻傻搞不清楚?其實啊,與其花費大精力給你解釋什麼「地址」、「指針」、「指向」等這些費解的抽象的概念,還不如用我發明的「己他」概念來解釋這個問題。

  1. ptr和value就是ptr的己值
  2. *ptr就是ptr的他值
  3. value就是ptr的他值

從2和3就可以得知,*ptr就是value,都是他值;ptr就是value,都是己值,所以用我的「己他」法一句話就解釋完畢,一句話你就能理解,還費啥勁兒再去解釋什麼地址不地址的!

關於指針的「己他」文章在我的圈子「C語言解惑課堂」從【第104篇】開始有講,題主有興趣的話可以在我的微信公眾號「C語言編程技術分享」的主頁回復「1111」加入圈子,從【第104篇】開始查看,也可以回復「1112」查看圈子所有的C語言答疑文章。


其實理解就行,這是「定義即初始化「,比如數組只有在定義時才能初始化

char a[10] = {0};而定義之後是不能這樣寫的a = {0};

同樣引用int a= x;指針 int *p = x;都是定義即初始化的寫法,

和賦值寫法是不一樣的(當然引用沒有賦值寫法)。

再反過來理解,可以使用#define或者typedef將指針類型定義成PINT

那麼PINT p = x;就不難理解了,所以在讀寫代碼的時候,將*號和類型一起來看就好理解了


在C語言和C++中,運算符 * 有以下含義

  1. 二元運算符,表示乘法。例如: x = 3 * 2;
  2. 類型說明,表示指針。 例如: char x = c; char* p = x; 這裡的 * 號放在變數定義中,與其前面的類型char結合,表明 p 是一個字元指針變數。p後面的 「=」 則表示將變數 p 初始化為 字元變數 x 的地址。
  3. 一元運算符,表示解引用(dereference)。此時它只能放到已定義好的指針變數前面(不能用來定義變數)。例如: *p = e; 表示將 p 所指的那塊存儲區域(或者理解為p變數中保存的地址值所表示的那塊存儲區域)內存放的數據改寫為字元 e。

注意上面「2」中,我們說 char* p = x; 是對p初始化,而不說「為p賦值」。初始化通常與變數定義相關,而賦值與變數定義無關。區分初始化和賦值有助於我們理解指針變數、C++中的構造函數及構造函數初始化列表等概念。


在C語言中,還有其它一些運算符是多義的。

: 二元運算符位與運算,或者一元運算符取地址

-: 一元運算符負號,或者二元運算符減法

++和--: 前置自增/減; 後置自增/減


運算符多義很正常。

在C++中,運算符是可以像函數一樣重載的。本質上,運算符就是函數。只不過C++在重載運算符的時候,不能改變運算符的元屬性,比如不能將二元運算符 變成一元運算符。最經典的運算符重載是左移位運算符 &

在 Haskell中,甚至可以發明新的運算符。比如發明一個「?+?」運算符

x ?+? y = show x ++ " + " ++ show y ++ " = " ++ show (x + y)

這樣,編譯運行如下代碼

2 ?+? 3

得到輸出:

2 + 3 = 5


根據評論中的討論,補充關於 char* x, y; 的問題

指針變數定義時,有兩種寫法:(我們以 T 代表某種類型)

T* p; T *q;

不管哪種寫法,*作為指針類型的標識,僅僅對與其相鄰的那個變數起作用。也就是

T* p1, q1; T *p2, q2;

中僅p1和p2是T類型指針,而 q1和q2則是T類型。

C++他爹關於這個*的位置有如下說法:(C++ Style and Technique FAQ)

The choice between "int* p;" and "int *p;" is not about right and wrong, but about style and emphasis. C emphasized expressions; declarations were often considered little more than a necessary evil. C++, on the other hand, has a heavy emphasis on types.

A "typical C programmer" writes "int *p;" and explains it "*p is what is the int" emphasizing syntax, and may point to the C (and C++) declaration grammar to argue for the correctness of the style. Indeed, the * binds to the name p in the grammar.A "typical C++ programmer" writes "int* p;" and explains it "p is a pointer to an int" emphasizing type. Indeed the type of p is int*. I clearly prefer that emphasis and see it as important for using the more advanced parts of C++ well.


你可以這樣想:

int *ptr=i;

現在出現了一個變數ptr,給他賦值i;

向左看,這個ptr是一個指針。什麼樣的指針呢?再向左看,int類型的。


推薦閱讀:
相关文章