1. 程式人生 > >陣列變數與指標

陣列變數與指標

背景:完全的C初學者。。試圖搞清楚陣列的概念,做了一些小試驗,查了一些解釋,合成此文。

我們說陣列變數相當於常量指標,那麼實際它就是常量指標名嗎?

簡單試驗:

 1 #include <stdio.h>
 2 
 3 int main() {
 4     int a; //宣告int變數
 5     printf("變數的地址:%p\n",&a); //宣告變數時,申請記憶體地址
 6     printf("變數佔位:%d\n",sizeof(a)); //根據型別決定分配空間
 7     // printf("變數的值:%d\n",a);  //報錯,因為沒有放入值
8 a = 9; 9 printf("變數的值:%d\n\n",a); 10 11 12 int *p; //宣告指標變數 13 printf("指標變數的地址:%p\n",&p); 14 printf("指標變數佔位:%d\n",sizeof(p)); 15 // printf("指標變數指向:%d\n",*p); //報錯,因為沒有放入值 16 p = &a; 17 printf("指標變數的值:%p\n",p); 18 printf("指標變數指向:%d\n\n",*p); 19 20
21 int s[4]={5}; //宣告陣列變數 22 printf("陣列變數的地址:%p\n",&s); 23 printf("陣列變數的地址+1:%p\n",&s+1); 24 printf("陣列變的地址佔位:%d\n",sizeof(&s)); //sizeof(地址) 25 printf("陣列變數的值:%p\n",s); //陣列變數的值的自己的地址!是一個特殊的指標! 26 printf("陣列變數的值+1:%p\n",s+1); 27 printf("陣列變佔位:%d\n",sizeof(s)); //sizeof(地址)?
28 29 30 printf("陣列變數首元素的地址:%p\n",&s[0]); //s和s[0]地址相同! 31 printf("陣列變數次元素的地址:%p\n",&s[1]); //陣列是變數的容器 32 printf("取陣列首元素:%d\n",s[0]); 33 printf("對陣列變數解指標操作:%d\n",*s); //s指向的東西就是s[0]! 34 printf("陣列元素佔位:%d\n\n",sizeof(s[0])); 35 36 37 38 //指標變數和陣列變數互相s賦值 39 int b=88; 40 int *const p2=&b; //常量指標必須在宣告的時候初始化! 41 p = s; //可以改變指標p的值 42 // p2 = p; //常量指標不可修改! 43 // s = &b; //陣列變數不可修改! 44 int s2[5]; 45 printf("陣列變數s2的地址:%p\n",&s); 46 printf("陣列變數的值:%p\n",s); //地址相同?? 47 // s2 = s; //陣列變數不可修改! 48 49 return 0; 50 }
View Code

輸出:

可以看出來:

  • 陣列變數符合指標的定義
  • 陣列變數的值就是陣列首元素的地址
  • 陣列變數不可修改,類似於常量指標

其中不解的是

  • 用&取陣列變數的地址,發現與陣列首元素的值的地址相同,即s與&s的值相同。
  • 如果陣列變數就是指標的話,那麼陣列變數的值為其首元素的地址,而它自己不應該放在另一個地址嗎?(就像上面的指標變數p一樣)

於是,查閱了一下,這個問題大致是這樣理解的

  • arr 本身是左值(但不可僅憑此表示式修改),指代陣列物件。不過 arr 會在大多數場合隱式轉換成右值表示式 &(arr[0]) 。為指標型別,指向 arr[0] 。
    &arr 是右值表示式,為指標型別,指向 arr 本身。簡單來說就是 arr 本身不是地址而是指代整個陣列,只不過會隱式轉成指標罷了arr (轉換後)和 &arr 型別不同數值相等是因為 arr 和 arr[0] 地址相同,這裡地址指首地址。【轉自知乎-暮無井見鈴

另有一份總結:

  • 陣列地址與陣列名:
    • 陣列名代表陣列首元素的地址(a);
    • 陣列的地址需要用取地址符&才能得到(&a);
    • 陣列首元素的地址值與陣列的地址值相同
    • 陣列首元素的地址陣列的地址兩個不同的概念
  • 陣列名的盲點:
    • 陣列名可以看做一個常量指標;
    • 陣列名“指向”的是記憶體中陣列首元素的起始位置;
    • 在表示式中陣列名只能作為右值使用下
  • 下列場合中陣列名不能看做常量指標:
    • 陣列名作為sizeof操作符的引數;
    • 陣列名作為&運算子的引數

    

驗證s與&s類別不同

  s與&s值相同,但s+1與&s+1值不同