1. 程式人生 > >C語言陣列與指標並不相同---《C專家程式設計》

C語言陣列與指標並不相同---《C專家程式設計》

1. 陣列和指標的訪問

初接觸C語言時,常發現在很多情況下陣列和指標的使用是可以互換的,因此對兩者的區分相對含混不清。但在某些情況下卻編譯報錯無法執行,比如在一個檔案中定義為陣列int s[100];在另一個檔案中宣告為指標extern int *s;兩者間將會因為型別不匹配而報錯。

首先,從陣列與指標名區分,陣列名是一個不可修改的常量,而指標名是一個可以修改的變數,因此如下圖所示,陣列名不可作為被賦值物件,而指標可以: 地址與地址的內容之間的區別 其次,陣列名相當於地址,其記憶體放該陣列的首個元素,而陣列元素是挨個存放在連續記憶體中的,可以通過陣列名 + 偏移量(下標)直接訪問某個特定元素;指標名雖然也相當於地址,但其記憶體放的仍是地址,通過指標名 + 下標訪問某個元素是先取出指標名對應地址記憶體放的地址,然後再加上下標偏移量得出存放該元素的地址,屬於間接訪問。 陣列的下標引用

對指標的引用 對指標下標的引用 最後,陣列與指標的其他區別如下表示:

指標 陣列
儲存資料的地址 儲存資料
間接訪問資料,首先取得指標的內容,把它作為地址,然後從這個地址提取資料;如果指標有下標,p[i]是把指標p的內容加上i作為地址並從中取得資料 直接訪問資料,a[i]只是簡單的以(a+i)為地址取得資料
通常應用於動態資料結構 通常用於儲存固定數目且資料型別相同的元素
相關的函式為malloc(), free() 隱式分配和刪除
通常指向匿名資料 自身即為資料名

陣列和指標雖然都可以在它們的定義中用字串常量進行初始化,但定義指標時,編譯器並不為指標多指向的物件分配空間,而只是分配指標本身的空間,除非在定義時同時賦給指標一個字串常量進行初始化(初始化指標時所建立的字串常量被定義為只讀,無法通過指標修改字串的值,且只能通過字串常量初始化指標,而不能通過數值常量初始化指標)。

2. 陣列和指標的可交換性

陣列主要有宣告(定義算是分配記憶體空間的特殊宣告)和使用兩種場景,一般情況下宣告(想了解關於宣告的解析,可參考《分析C語言的宣告》)不可以混用,在表示式中的使用可以混用,但是C編譯器在編譯時都把作為函式引數的陣列名轉換為指標,所以在陣列作為函式引數宣告時跟指標形式是等效的。 什麼時候陣列與指標相同 上表源於ANSI C的三條規則:

  1. 表示式中的陣列名(與宣告不同)被編譯器當作一個指向該陣列第一個元素的指標;
  2. 下標總是與指標的偏移量相同; 規則3.規則2. 下標總是與指標的偏移量相同;
  3. 在函式引數的宣告中,陣列名被編譯器當作指向該陣列第一個元素的指標。

上面談到的都是陣列可以轉換為指標的情況,比如在表示式中和在函式引數的宣告中陣列名與指標是等效的,但在其他情況下定義與宣告必須匹配;需要強調的一點是,指標始終就是指標,你雖然可以用下表形式訪問指標,但絕不可以改寫為陣列。

3. 多維陣列與指標陣列

  1. 嚴格說C語言並不直接支援多維陣列,而是通過“陣列的陣列”的形式實現多維陣列的效果。比如三維陣列char array[i][j][k]不能寫為char array[i,j,k]。
  2. 陣列識別符號[]優先順序基本處於最高階,且遵循從左到右的結合順序,所以最右側的下標在連續記憶體塊兒中是最先變化的。 多維陣列的儲存
  3. 由於多維陣列也是以線性排列在連續記憶體塊兒中,故多維陣列可以通過表示式運算降維訪問,比如訪問array[i][j][k]也可以通過array[i*j_max*k_max + j*k_max + k]訪問(j_max, k_max分別是j, k所在維度的元素總數)。
  4. 陣列的陣列array[i][j]可以表示為指標陣列*array[i]的形式,它們都被C編譯器解釋為 *(*(array+i)+j)。但正如指標與陣列不完全等效一樣,陣列的陣列與指標陣列也不完全等效,兩者的訪問過程如下所示: 一個數組的陣列 一個字串指標陣列
  5. 陣列的陣列每行長度需要一致(需要以行長度作為判斷每行是否結束的依據),靈活性受限;字串指標陣列則每行的長度可以不一樣(字串指標可以以每行字串末尾的NUL判斷該行是否結束),使用比較靈活。
  6. C語言並不能直接把陣列的陣列作為函式引數傳遞給一個函式,函式引數也是被編譯為指標形式傳遞給函式的,常見的作為引數傳遞多維資料的形式有字串指標陣列my_function(char *my_array[]),或指標的指標my_function(char **my_array),二者是等價的,作為函式引數編譯結果一致。
  7. C語言也不能通過函式呼叫返回一個數組,而只能返回一個指標,可以是任何資料型別的指標,比如陣列指標int (*array)[i],結構體指標struct *p等,但除了函式返回值型別匹配外,需要注意的是要返回的指標不能是函式體內定義的區域性指標變數(可以是全域性變數或static變數),因函式返回後在函式體內定義的區域性變數生命週期已經結束,後續引用返回指標會導致錯誤。
  8. 最後強調的一點是,指標可以通過malloc(), free()在執行時動態分配記憶體空間(陣列在定義時分配記憶體空間),而且可以根據後續需要通過realloc()函式進行動態空間擴容或縮減。