C指標和陣列的關係詳解

駿馬金龍發表於2019-03-26

部落格園的我:駿馬金龍: www.cnblogs.com/f-ck-need-u

1.C中陣列和指標的關係

對於任意型別的陣列arr,對於同型別的指標型別parr(確切一點,可以假設型別為int,即int arr[], *parr)。它們之間有如下"內幕":

1.陣列的名稱arr本身就是一個指標,這個指標指向陣列的第一個元素

C指標和陣列的關係詳解

2.因為名稱arr本身是指標,所以可以直接賦值給同型別的指標parr:parr = arr,這使得parr也指向陣列的第一個元素,所以這個賦值過程等價於parr = &arr[0]

C指標和陣列的關係詳解

3.指標和陣列名在效果上是等價的。它們的區別在於:指標是變數。指標變數可以參與表示式的計算,如parr++parr=arr是有效的,而arr=parrarr++是無效的
4.陣列的各元素在記憶體中是連續的,可以通過索引下標的方式arr[i]獲取任意一個元素,而arr[i+1]一定代表下一個元素(除非陣列索引越界),arr[i-1]一定代表前一個元素(除非沒有前一個元素)
5.因為陣列名也是指標,所以也可以將獲取元素的方式寫成*(arr),它等價於arr[0],即代表第一個元素的值。同理,*(arr+1)等價於arr[1]即表示第二個元素,*(arr+i)等價於arr[i]即表示第i+1個元素
6.也就是說,arr代表第0個元素的地址,arr+1代表第2個元素的地址,arr+i代表第i+1個元素的地址
7.也可以直接通過指標的加減法運算取得對應位置的元素地址parr代表的是第一個元素(index=0)的地址,parr+1代表第二個元素(index=1)的地址,parr+i代表第i+1個元素(index=i)的地址
8.所以,*(parr)代表的是陣列第一個元素的值,*(parr+1)代表陣列第二個元素的值,*(parr+i)代表陣列第i+1個元素的值

C指標和陣列的關係詳解

9.實際上,陣列索引下標運算就是先轉換成對應的指標,再通過指標去取得對應元素的。所以,使用指標的效率比使用索引下標取陣列值的效率要高,它少了一個轉換過程。或者說,指標和陣列的索引是一一對應的關係
10.由於陣列名指向的是陣列的第一個元素,如果某個指標指向這個陣列中的某個元素,那麼可以說這個指標指向的就是一個子陣列。例如arr是原始陣列,那麼parr+3是一個子陣列,arr+4也是一個子陣列。這使得我們可能訪問到陣列第一個元素之前的元素(即父陣列中子陣列之前的元素),比如-1、-2在操作上都是允許的,除非這樣的訪問超越了父陣列的邊界

2.指標和陣列之間的幾個等價概念

          等價的方式              |      意義
--------------------------------|---------------------
&arr[i]    arr+i      parr+i    |  都表示index=i元素的地址
--------------------------------|---------------------
arr[i]     *(arr+i)   *(parr+i) |  都表示index=i元素的值
複製程式碼

特別的,當i=0時:

&arr[0]    arr      parr      都表示陣列第一個元素的地址
arr[0]     *(arr)   *(parr)   都表示陣列第一個元素的值
複製程式碼

3.指標運算

指標是變數,可以直接參與表示式的運算,指標是地址,可以進行地址運算。

有效的指標運算包括:

  1. 相同型別指標之間的相互賦值運算
  2. 指標與整數之間的加、減法運算。這種運算可以讓指標前移或後移N個陣列的元素
  3. 指向相同陣列中元素的兩個指標之間的減法或比較運算(指標與指標之間只能進行減法和比較),減法運算得到的結果是指標之間的元素個數(例如(arr+3) - arr + 1表示第1個元素到第4個元素之間的4個元素)
  4. 0賦值給指標的運算、0轉換成指標型別的空、指標和0之間的比較
  5. 其它的運算方式都是非法的

對於指標和整數之間的加減法或指標的自增、自減運算,需要注意的是這些運算子之間的優先順序以及從右向左計算的方式。

parr += 1表示將指標向後移動一位,等價於++parr

*++parr表示取下一個陣列元素,因為一元運算子*++的優先順序相同,它們從右向左運算。

*parr++表示取得parr當前指向的元素,但是parr已經指向下一個元素了。

指標之間可以比較大小,當然,只有指向同一陣列的多個指標之間的比較才有意義。p和q兩個指標,如果p指向的元素在q指向的元素之前,那麼p < q。通過比較指標,也可以很容易判斷陣列的訪問是否越界。例如,判斷指標指向的元素是否在第99個元素之後,對於只有100個元素的陣列來說,這就是在判斷越界。

parr > &arr[99]
parr > arr + 99  // 與上等價
複製程式碼

同理,指向同一陣列的多個指標之間可以進行減法運算(只能進行減法),指標之間的減法運算返回的是這兩個指標之間的元素個數

4.指標、陣列和函式

C語言是按值拷貝的。

但因為陣列名本身就是指向第一個元素的指標,所以按值拷貝也只是拷貝這個指標,拷貝得到的指標副本仍然指向陣列的第一個元素,並且通過這個指標能夠遍歷到後面的元素。

因為拷貝後得到的副本指標指向的仍然是函式外面的陣列結構,所以在函式內部可以直接通過這個指標修改外部陣列。

下面兩種想要以陣列作為引數的函式在行為上是等價的

void func1(int arr[]){}
void func1(int *parr){}
複製程式碼

呼叫該函式時,都可以傳遞陣列名或指標給它們:

int arr[];
int *parr;
parr = arr;

func1(arr);
func1(parr);
複製程式碼

相關文章