如何理解c/c++語言的聲明以及類型?

完全不懂,感覺這個比指針複雜至少20倍。

http://1.int a 表示a是一個int類型

↑↑↑↑↑題主就懂上面一個 ↑↑

按照我所觀察到的編譯器的邏輯:

int* a則表示a是(int*)類型?

int** a則表示a是(int**)類型,那麼問題來了,*到底是什麼玩意。

還有c++當中的引用:intb=a。

明明表示的是a是b的別名,其實告訴我們的道理就是,a其實就是b

所以我畫了一張圖:

所以此時a就是b,所以b的類型是int,而不是int。

還有int *p[5]是什麼東西

p的類型又是什麼

還有int (*p[5])()是什麼.....

最後,c專家編程第三章我一個字都看不懂。

因為我連int*是什麼都不知道


首先說一下C語言變數聲明的邏輯

C語言用的是解方程式的聲明法,什麼是解方程

int*a;表示有這麼一個變數a,*a運算(解引用a)的類型是int,所以a是指向int的指針

同理

int arr[10]表示有這麼一個變數arr,arr[i]運算(帶偏移量的解引用)得到的類型是int,所以arr是10元素的int數組

函數也一樣

int func(int, int),有這麼一個東西,用兩個int調用它(括弧也是運算符知道吧),得到一個int,所以func是個接受兩個int,返回一個int的函數

所以有人習慣尊重C的解方程式的聲明,把*挨著變數名寫,這樣聲明和使用的寫法一致,但是我不喜歡

然後說你題目里那個複雜聲明int(*p[5])()

看外層,int(xxxx)(),說明內層東西的類型是個函數,接受空,返回int

看內層,*p[5],解方程:對p進行[]運算,再進行*運算,得到了外層一個接受空返回int的函數

所以p是什麼,p是一個數組,5個元素,每個元素是一個指針,指針指向函數,函數接受空返回int

GitHub - MichaelSuen-thePointer/mqcdecl: A "clean room" and "naive" implementation of cdecl.org

今天上午剛寫了一個C語言複雜聲明翻譯器,你這裡就用上了。

這種複雜聲明實際工程里不能寫,但是你不能不清楚他的原理,他們本質都是解方程

============更新一下

覺得這裡說的不是很明確,於是我寫了一篇博客,地址在這裡淺談C語言變數聲明的解析

============更新結束

然後指針是什麼

對於x86的棧內存模型,局部變數儲存在棧中,棧是操作系統給程序開闢的一塊線性的內存空間,變數在其中線性排布,既然是內存空間,那就會有對應的地址用來向操作系統/計算機底層硬體存取這塊內存空間,指針就是一個用來裝內存地址的變數。

你聲明了一個變數int a;對應的彙編代碼就會在棧上給你分配一個4byte的空間(具體怎麼分配的參見x86彙編以及cdecl調用約定),當你修改這個int的時候,儘管你沒有在C語言里直接使用指針,對應的彙編代碼依然是用那個int的內存地址來修改它的。當你取地址的時候,對應彙編代碼就會拿到這4byte空間的第一個位元組對應的內存地址。你聲明了一個指針變數int*p;,同樣作為一個變數,內存中也會有一塊對應的空間給這個變數,當你把取到的a的地址賦給p的時候,前面拿到的那個地址作為一個值,就存到了p這個變數所佔據的4個byte空間里。這就是指針。

至於C++的int,內部實現也是多半用的指針,不過引用相比表意更不明確的指針,很多情況下是可以優化的,有時也不一定用指針。


很簡單,從被聲明的標識符開始,先右後左,遇括弧返回。

int A;

很簡單,A是一個int

int *A;

從A開始:A是一個變數,*表示它是一個指針變數,int表示這個指針變數指向int

int **A;

A是一個變數,*表示它是一個指針變數,第二個*表示前一個指針變數指向的類型還是一個指針,int表示A這個指針變數指向的指針變數指向一個int

int A[5];

A是一個變數,(向右)這個變數是一個有5個元素的數組,(向左)這個數組存儲int

int *A[5];

A是一個變數,(向右)這個變數是一個有5個元素的數組,(向左)這個數組存儲指針,指針指向的類型是int

int **A[5];

A是一個變數,(向右)這個變數是一個有5個元素的數組,(向左)這個數組存儲指針,指針指向的類型還是一個指針,最終指向的數據類型是int

當然還有很多更為複雜、連老鳥都能搞暈的寫法。那些就屬於魔道了。

真需要作複雜的聲明時,建議用typedef一層層定義別名、最後用typedef的別名完成聲明。這樣寫出的聲明易懂、無歧義、便於閱讀。

C語言複雜聲明解析


《深入理解計算機系統》,回答你所有問題。但是考慮到這本書可能對初學者不太友好,簡單說一下:

首先內存的作用和紙差不多。

int a = 1; /* 在紙的第一行位置寫一個1(請嘗試用筆寫下來)。 */
int * b = a; /* 在紙第二行位置寫下:「第一頁第一行有一個int」(在內存中保存的東西一般是0x0101這樣的東西) */
*b = 2 /* 把第二行指示的位置的數據修改為2 */
b = 0x0202 /* 第二行修改為:「第二頁第二行有一個int」(實際上可能並沒有)*/

其他問題,恕答主很懶,答主覺得解釋清楚指針是什麼,其他問題也就很好理解了。提示一下,代碼和數據一樣要被載入到內存中的,也是有地址的。

PS:多看書。


沒錯int*就是一個類型,至於為什麼要有int*這樣的類型原因很簡單,這門語言就是需要這麼一種類型才能完成一些事情,而int做不到。

int*和int的區別在於,int就是一個int,只要關心它的值就可以了,而int*除了本身值有意義之外,還可以進行一次解引用

int a = 1;

int *pa = a;

這個例子中,a的值是1這是我們關心的,而a的地址(假設是0x12345678)是我們不需要關心的。

pa的地址(假設是0x87654321)我們不需要關心,而它的值是0x12345678就是有意義的,另外pa還可以解引用一次,*pa的結果是1

所以int*是一個類型,並且這個類型是C語言必須要的

多維指針理解也簡單,每加一個*,就可以多解引用一次

同理int是C++語言必須要的一種類型,理由類似

所以題主第二個問題中的說法是不對的,b是int類型,而不是int類型。如果b是int,那它就做不到引用的功能了。

int *p[5]

就是指針的數組,這個數組中有5個int*,分別用p[0],p[1],p[2],p[3],p[4]訪問

int (*p[5])()

這是函數指針數組,請看栗子

int fun1()
{
return 1;
}
int fun2()
{
return 2;
}
int fun3()
{
return 3;
}
int fun4()
{
return 4;
}
int fun5()
{
return 5;
}
int _tmain(int argc, _TCHAR* argv[])
{
int(*p[5])();
p[0] = fun1;
p[1] = fun2;
p[2] = fun4;
p[3] = fun4;
p[4] = fun5;
printf("%d
", p[0]());
printf("%d
", p[1]());
printf("%d
", p[2]());
printf("%d
", p[3]());
printf("%d
", p[4]());
getchar();
return 0;
}


研究一下c++操作符的作用,優先順序,以及結合性表格就能搞清楚。

簡單來說,只需要記住以下四點。

1)指針"T *a",數組"T a[...]",函數"T a(...)",T可嵌套,a可省略(作為類型)

2)A*B[...] 等於 A*(B[...]) ,A *B(...) 等於 A *(B(...)),必要時加括弧

3)假如op1,op2各自代表*,,或,那麼 ... op1 B op2 ... 等於 ... op1 (B op2 ...)

4)如果和連續出現,只有... ... 等於 ... ...,其餘情況為... ...

PS:「c專家編程第三章我一個字都看不懂」,一看就沒好好讀過KR,基礎太爛。


有時候編譯器就是那麼怪,C++編譯器更怪。你結合內存圖消化了就好,不要糾結語法細節,畢竟你不是做編譯器的。


呵呵,比指針複雜20倍啊...

int a

中間加一個*,指針

中間加兩個*,指針的指針

中間加三個*,指針的指針的指針

如果不談指針,你可以想成爸爸

int a的爸爸,

的爸爸的爸爸

的爸爸的爸爸的爸爸

如果還不行,我們上一首後現代兒歌(來自 小蓓蕾組合)

/**********************************************/

  • (白)爸爸好,媽媽好,爺爺好,奶奶好
  • 爸爸的爸爸叫什麼
  • 爸爸的爸爸叫爺爺
  • 爸爸的媽媽叫什麼
  • 爸爸的媽媽叫奶奶
  • 媽媽的爸爸叫什麼
  • 媽媽的爸爸叫外公
  • 媽媽的媽媽叫什麼
  • 媽媽的媽媽叫外婆
  • 相逢開口笑,嘴巴甜又巧
  • 叫得全家老少樂呀樂陶陶
  • 見誰都要叫,千萬別叫錯
  • 懂禮貌的孩子就是我就呀就是我
  • 爸爸的兄弟叫什麼
  • 爸爸的兄弟叫伯伯和叔叔
  • 爸爸的姐妹叫什麼
  • 爸爸的姐妹叫姑姑
  • 媽媽的兄弟叫什麼
  • 媽媽的兄弟叫舅舅
  • 媽媽的姐妹叫什麼
  • 媽媽的姐妹叫阿姨
  • 相逢開口笑,嘴巴甜又巧
  • 叫得全家老少樂呀樂陶陶
  • 見誰都要叫,千萬別叫錯
  • 懂禮貌的孩子就是我,就呀就是我
  • (白)外公好,外婆好,叔叔好,伯伯好
  • 爸爸的爸爸叫什麼
  • 爸爸的爸爸叫爺爺
  • 爸爸的媽媽叫什麼
  • 爸爸的媽媽叫奶奶
  • 媽媽的爸爸叫什麼
  • 媽媽的爸爸叫外公
  • 媽媽的媽媽叫什麼
  • 媽媽的媽媽叫外婆
  • 相逢開口笑,嘴巴甜又巧
  • 叫得全家老少樂呀樂陶陶
  • 見誰都要叫,千萬別叫錯
  • 懂禮貌的孩子就是我,就呀就是我
  • /**********************************************/
  • 標準有向無環圖,二叉樹不行

  • 好男人就是我,我就是int a


為實物 取外號

這可是門技術活, 要考慮怎麼把外號取得好聽(是否好記憶-&>好區分)!

取得響亮(能傳播多遠)!

還要讓人能快速通過外號找到實物(別太作,取超多的外號,還外號的外號...把人繞暈了)!


推薦閱讀:

TAG:程序員 | 編程 | C編程語言 | CC | C語言入門 |