首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C Primer Plus 第 10 章:陣列與指標深度解析

     編輯:關於C語言

第 10 章 陣列與指標

10.1 陣列基礎

陣列是由一系列相同類型元素組成的集合。宣告陣列時需指定元素個數與元素類型。

10.1.1 陣列初始化

有時需要唯讀陣列,即程式僅從陣列讀取數值而不寫入資料。此時初始化可使用 const 關鍵字。與一般變數相同,未初始化前陣列元素值不定。若初始值個數少於陣列大小,多餘元素自動初始化為 0;若完全不初始化,元素存放垃圾值;但若部分初始化,未指定元素則設為 0。初始化列表項目數超過陣列大小會導致編譯錯誤。可省略方括號內的數字,讓編譯器自動推斷大小。

為避免人工計算錯誤,可用 sizeof 運算子計算陣列大小。sizeof days 給出整個陣列大小(位元組),sizeof days[0] 則是單一元素大小。

10.1.2 指定初始化項目(C99)

C99 允許選擇性初始化特定元素,例如:int arr[6] = { [5] = 212 };

#include <stdio.h>
#define MONTHS 12
int main(void) {
    int days[MONTHS] = { 31, 28, [4] = 31, 30, 31, [1] = 29 };
    int index;
    for (index = 0; index < MONTHS; index++)
        printf("month %2d has %d days.\n", index + 1, days[index]);
    return 0;
}

若多次初始化同一元素,最後一次生效。宣告陣列時方括號內只能用整數常數運算式;sizeof 運算式視為整數常數,但 const 值不是。且運算式值必須大於 0。C99 引入變長陣列(VLA)主要為了強化數值計算能力。

10.2 多維陣列

二維陣列宣告:float rain[5][12];。rain 是含 5 個元素的陣列,每個元素類型為 float[12];rain[0][0] 是一個 float 數值。可視為 5 行 12 列的二維表格:改變第二個下標沿列移動,改變第一個下標沿行移動。初始化時每行用花括號括起,也可省略內層括號僅保留最外層,不足部分自動補 0。同樣適用於三維陣列。

10.3 指標與陣列

陣列下標實際是指標運算的語法糖。陣列名即首元素地址:fizny == &fizny[0],兩者皆為常數。C 語言中指標加 1 會增加其指向類型大小的位元組數;對陣列而言,地址遞增至下一元素而非下一位元組。fizny + 2 == &fizny[2],*(fizny + 2) == fizny[2]。注意 *(fizny + 2) 與 *fizny + 2 的區別:間接運算子 * 優先級高於 +,後者等價於 (*fizny) + 2,前者為第三個元素值。

函數原型中可用 int *ar 替代 int ar[]。傳遞陣列名給函數時,函數內無法得知陣列大小。解決方法:1. 約定固定大小;2. 將大小作為第二個參數傳遞。也可傳遞兩個指標,分別指向起始與結束位置(結束指標指向最後一元素之後,C 保證此指標合法)。*start++ 中 * 與 ++ 優先級相同但右結合,建議寫作 *(start++) 以利閱讀。

10.4 指標操作

指標基本操作包括:賦值取值(* 取出指向地址的值)、取指標地址(& 取得指標本身地址)、整數加減指標(按指向類型大小乘積移動)、指標增減、指標相減求距離(單位為元素類型大小)、指標比較(需同類型)。C 保證指向陣列元素及陣列尾後一位置的指標有效,超出範圍行為未定義。不可對未初始化指標取值,否則可能破壞資料或導致崩潰。建立指標時系統僅分配儲存指標本身的空間,不分配資料空間。

10.5 保護陣列內容

函數接收陣列參數可能破壞原始資料。可在形式參數宣告中使用 const 關鍵字防止修改。

10.5.1 關於 const 的補充

指向常數的指標不可修改數值:

double rates[5] = { 88.99, 100.12, 59.45, 183.11, 340.5 };
const double *pd = rates;
*pd = 29.89;      // 不允許
pd[2] = 222.22;   // 不允許
rates[0] = 99.99; // 允許
pd++;             // 允許
const double locked[4] = { 0.08, 0.075, 0.0725, 0.07 };
double *pnc = locked; // 非法

雙重 const 可建立不可改指向位址也不可改資料的指標:const double *const pc = rates;

10.6 指標與多維陣列

int zippo[4][2]; 中 zippo 值等同 &zippo[0]。zippo[0] 本身是含兩整數的陣列,其值等同 &zippo[0][0]。zippo 是兩整數大小物件的地址,zippo[0] 是一整數大小物件的值,兩者數值相同但類型不同。指標加 1 會加上對應類型大小,故 zippo + 1 與 zippo[0] + 1 結果不同。*(zippo[0]) 為 zippo[0][0] 值,*zippo 為 &zippo[0][0],**zippo 等價 zippo[0][0]。zippo[2][1] 的指標表示為 *(*(zippo + 2) + 1)。

10.6.1 指向多維陣列的指標

int (*pz)[2];  // pz 指向含兩個 int 的陣列
int *pz[2];    // 建立指標陣列

指標類型匹配規則:int *pt; int ar[3][2]; int **pd; 中 pd = &pt 合法(指向指標的指標),*pd = ar[0] 合法(指向元素的指標),pd = ar 非法。const 限定詞傳遞規則:p1 = p2 非法,p2 = p1 合法,pp2 = &p1 非法。函數參數中除最左方括號可留空外,其餘維度必須指定大小。

10.7 變長陣列(VLA)

C99 引入 VLA,允許用變數指定維度大小:

int quarters = 1, regions = 5;
double sales[regions][quarters];

限制:VLA 必須為自動儲存類別(函數內部或參數宣告),宣告時不可初始化。「變長」指大小可由變數決定,非創建後可改變大小。函數原型可寫作 int sum2d(int rows, int cols, int ar[rows][cols]);,C99 允許省略參數名並用 * 代替:int sum2d(int, int, int ar[*][*]);

10.8 複合字面值

複合字面值建立無名陣列:(int [2]){10, 20};,可省略大小 (int []){50, 20, 90};。因無名稱,必須在創建同時使用,常以指標保存位址:int *pt1 = (int [2]){10, 20};

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved