C中 數組和指針的異同

數組在不少狀況下是和指針等價的,數組的下標運算和指針的解引用也有等價形式:arr[i] == *(arr + 1);可是也有一些狀況下數組和指針是不同的:extern int arr[]; extern int *arr;編程

這裏持續記錄一下指針和數組的異同(如下來自於C專家編程)數組

首先明確一下幾個定義:數據結構

  • 聲明和定義:C語言中的對象必須有且只有一個定義,可是能夠有多個extern聲明
定義 只能出如今一個地方 肯定對象的類型並分配內存,用於建立新的對象。例如:int my_array[100]
聲明 能夠屢次出現 描述對象的類型,用於指代其餘地方定義的對象(例如在其餘文件裏)例如:extern int my_array[]
    • 區分定義和聲明:
      • 聲明至關於普通的聲明:它所說明的並不是自身,而是描述其餘地方的建立的對象
      • 定義至關於特殊的聲明:它爲對象分配內存
  • 左值和右值(地址和地址的內容):

        注:C語言引入了"可修改的左值"這個術語,可修改的左值指的是能夠放在賦值語句左邊。這個術語是爲了與數組名區分,數組名也用於肯定對象在內存中的位置,也是左值,但它不能做爲賦值的對象。所以,數組名是個左值但不是可修改的左值。函數

  1. 指針與數組的不一樣:
    •  編譯器爲每一個變量分配一個地址(左值),這個地址在編譯時可知,並且該變量在運行時一直保存於這個地址。相反,存儲於變量中的值(它的右值)只有在運行時纔可知。若是須要用到變量中存儲的值,編譯器就要發出指令從指定地址讀入變量值並將它存於寄存器中。因此,若是編譯器須要一個地址來執行某種操做,它就能夠直接進行操做(由於符號的地址在編譯時可知),並不須要增長指令首先取得具體的地址。相反,對於指針,必須首先在運行時取得它的當前值(取得指針自己所存的右值),而後才能對它進行解除引用操做。
    • 故:int a[100] 和 extern int a[]都代表a是一個數組,也就是一個內存地址,數組內的字符能夠從這個地址找到。從數組提取一個字符,只要簡單的從符號表顯示的a的地址加上下標,須要的字符就位於這個地址中。相反,若是聲明extern int *p,它告訴編譯器p是一個指針,它指向的對象時一個字符。爲了取得這個字符,必須獲得地址p的內容(注意數組a自己就是一個地址),把它做爲字符的地址並從這個地址中取得這個字符,相比數組a來講多了一次額外的提取。取a中的字符和p所指的字符見下圖:

 

    • 由上可知,int a[100] 告訴編譯器a是一個數組,自己就是一個地址。int *p告訴編譯器p是一個指針,p所在的地址中存的是一個int的地址。

下面繼續對數組和指針進行解釋:"當定義爲指針,但以數組方式引用"時會發生什麼spa

    • 這時編譯器所執行的是對內存進行間接引用。之因此會如此是由於咱們告訴編譯器咱們擁有的是一個指針。

                對照上圖的訪問方式:
                    char *p = "abcdefg";    ...... p[3]
                    和
                    char a[] = "abcdefg";    ...... a[3]
                    這兩種狀況均可以取得字符'd',但二者的途徑卻很不同。3d

                 當寫了extern char *p的時候,編譯器將會:
                     a.取得符號表中p的地址,提取存儲於此處的指針
                     b.把下標所表示的偏移量與指針的值相加,產生一個地址
                     c.訪問上面這個地址,取得字符。指針

    • 考慮若是p被聲明爲extern char *p;可是它原先的定義倒是char p[10];這種情形。當用p[i]這種形式提取這個聲明的內容的時候,實際上獲得的是一個字符。可是按照上面的方法,編譯器確把它當成是一個指針,就會先去取這個地址中所存的地址,可是其實p的地址中如今存的其實已是一個int型了,吧ASCII字符解釋爲地址顯然是驢脣不對馬嘴。相反的,若是p被聲明爲extern char p[];可是它原先定義倒是int *p;這種情形的話,那麼p[i],編譯器會直接取地址(p + i),顯然這也是不對的,由於此時直接把p的地址和i相加實際上是一個不存在的地址。
    • 可見數組和指針在這種狀況下是不一樣的。在C語言中,對數組的引用其實引用的是地址自己(不可變左值),可是對指針的引用實際上是引用指針所在地址中的內容(右值)。

 

 

數組和指針的其餘區別對象

指針 數組
保存數據的地址 保存數據

間接訪問數據,首先取得指針的內容,把它做爲地址,而後從這個地址提取數據。blog

若是指針有一個下標[I],就把指針的內容加上I做爲地址,從中提取數組內存

直接訪問數據,a[I]只是簡單的一a + I爲地址取得數據
一般用於動態數據結構 一般用於存儲固定數目且數據類型相同的元素
相關的函數爲malloc(),free() 隱式分配和刪除
一般指向匿名數據 自身即爲數據名

    2.數組和指針的相同點:


除了上面的幾種不一樣的狀況之外,不少狀況下數組和指針是能夠等同看待的,例如在做爲函數的形參的時候,數組和指針是等價的:void foo(int *); == void foo(int[]);

不少狀況下咱們使用數組和指針的時候也是很是相似的,例如 arr[n] == *(arr + n)

相關文章
相關標籤/搜索