回覆列表
  • 1 # 使用者4849703631976

    C 語言中的一個表示式,除了有值以外,還有型別。不同的表示式,雖然值可能一樣,但是因為型別的不同,會導致不同的現象。比如定義 int a=1; char b=1; 之後,雖然 a 和 b 的值都是 1,但是它們一個是 int 一個是 char。編譯器在編譯程式的時候會“推導”表示式的型別。例如 1 (int) + 1.0 (double) 會得到 2.0 (double),這裡面不僅有數學運算,同時還有型別的推導。

    int *p 指向了 0x1234 這個地址,p+1 這個表示式會得到一個“int *”型別的指標,其值是 0x1238。為什麼不是 0x1235 呢?因為一個 int 的大小是 4 個位元組。指標的 +1 表示這個 int 後面的下一個 int 的地址,一個 int 佔 4 位元組空間,假設得到 0x1235 的話就和之前位於 0x1234 的 int 重疊了。

    還可以舉一些例子,比如 a 是 int,“&a” 這個表示式的型別就是 int *,其值是 a 的地址。如果 p 是 int * 型別的指標,“*p”這個表示式的型別就是 int。陣列也是一樣,例如我們定義 int a[10][10],這個時候 a 的型別是 int [10][10],a[0] 的型別是 int [10],a[0][0] 的型別才是 int。C 語言中的多維陣列本質上就是陣列的陣列,例如 typedef int my_type[5]; mytype a[10]; 和 int a[10][5]; 是等價的。(這樣理解:my_type 表示有 5 個 int 的陣列,a 是 10 個“my_type”組成的陣列。)對“X 型別的陣列”取下標,得到的結果就是 X 型別。C 語言中陣列名可以當指標用,X 型別的陣列,可以當指向 X 型別的指標用,例如定義 int a[10],這時候 a 可以當 int * 型別用,等價於陣列第一個元素的地址,即 &a[0]。(注:但是陣列和對應的指標型別仍然是兩個不同的型別,例如 sizeof 中有區別,例外是函式形參中寫陣列和指標是完全等價的,如果看不懂括號裡這句話可以忽略。)

    對一個變數取地址,得到的是它起始位置的地址,所以如果我有 int a[10] 這樣的陣列,作為一個整體(40 個位元組!),這個整體的地址和它第一個元素(4 個位元組)的地址當然是一樣的。但是!它們的型別不同!直接寫“a”,相當於 &a[0],是指向一個 int 的指標(型別為 int *),而如果你寫 &a,那你得到的是 a 這個陣列的地址,是指向 int [10] 的指標(型別為 int (*)[10])。

    注:根據 C 語言優先順序的定義,int *p[10] 表示 10 個“指向 int 的指標”構成的陣列,是 10 個指標!而 int (*p)[10] 表示一個指向“10 個 int 形成的陣列”的指標,是 1 個指標!一個指向陣列的指標!

    之前說到,指標型別進行運算的時候,p+1,p-1 增加或者減少的其實是指標指向的東西的大小。所以你把一個指向陣列的指標 +1,增加的地址就應該是陣列的大小。例如:

    程式執行的結果是相差 40 的兩個數。

    a[i] 等價於 *(a+i),這也是為什麼有人回答說 a[0] 可以寫成 0[a]。

    總結一下:C 語言的表示式除了值以外還有型別,在進行運算的時候型別也在變,不管進行多少次 &(取地址)和 *(解引用),你應該都可以推斷出結果的型別。型別會影響很多行為,例如指標的型別會影響指標進行運算時地址加減的量。對一個指標取 *(解引用),得到的東西可能是陣列或者指標,本身仍然表示一個地址,可以繼續取 *。陣列的地址和它第一個元素的地址是相同的,但是型別不一樣。printf 輸出一個指標的時候,你只能看到地址的值,看不到型別。

  • 中秋節和大豐收的關聯?
  • 結婚蜜月國外海邊島嶼蜜月(預算兩人3萬內),可以推薦下嗎?