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

深入理解C指標與陣列:記憶體模型、指標運算與多維陣列進階

     編輯:關於C語言

深入理解C指標與陣列:核心機制全解析

指標與陣列的關係是C語言最核心也最易混淆的主題。本文從記憶體模型出發,系統闡述指標與陣列的異同、指標運算機制、函數參數傳遞、動態記憶體管理、多維陣列佈局等進階主題,助你建立精確的心智模型。

核心觀念:指標 ≠ 陣列

陣列:連續儲存同質元素的固定大小記憶體區塊,陣列名稱在大多數表達式中退化為指向首元素的指標,但本質不同:

  • sizeof(array) 回傳整個陣列位元組大小
  • &array 型別為 int (*)[N](陣列指標),而非 int*
  • 陣列名稱不可作為左值(不可修改指向)

指標:儲存記憶體位址的變數,支援算術運算、間接存取、動態分配。

int vector[5] = {1,2,3,4,5};
int *pv = vector;           // 等價於 &vector[0],型別 int*
int (*pa)[5] = &vector;     // 型別 int (*)[5],指向整個陣列

printf("%zu\n", sizeof(vector));  // 20 (5*4)
printf("%zu\n", sizeof(pv));      // 8 (64位系統指標大小)
printf("%zu\n", sizeof(pa));      // 8
printf("%p %p\n", (void*)vector, (void*)&vector);  // 數值相同,型別不同

指標運算與陣列存取等價性

pv[i] 編譯器自動轉換為 *(pv + i),指標運算以元素大小為單位:

int *p = vector;
printf("%d\n", *(p+1));   // 2,相當於 p[1]
printf("%d\n", *(vector+1)); // 2,陣列名退化為指標

// 關鍵差異:指標可修改,陣列名不可
p++;        // 合法
vector++;   // 編譯錯誤:左值要求

一維陣列動態管理

malloc/realloc 彈性陣列

char* getLine(void) {
    const size_t INCREMENT = 10;
    char *buffer = malloc(INCREMENT);
    char *pos = buffer;
    size_t maxlen = INCREMENT, len = 0;
    int ch;

    while ((ch = fgetc(stdin)) != '\n' && ch != EOF) {
        if (++len >= maxlen) {
            maxlen += INCREMENT;
            char *newbuf = realloc(buffer, maxlen);
            if (!newbuf) { free(buffer); return NULL; }
            pos = newbuf + (pos - buffer);  // 維持相對位移
            buffer = newbuf;
        }
        *pos++ = ch;
    }
    *pos = '\0';
    return buffer;  // 呼叫者負責 free()
}

C99 變長陣列 (VLA)

void process(int n) {
    int vla[n];  // 僅限區塊作用域,生命週期隨函數結束
    // ...
}

函數參數傳遞:陣列退化為指標

// 以下三種宣告等價
void func(int arr[]);
void func(int arr[10]);  // 大小被忽略
void func(int *arr);     // 本質:傳遞首元素位址

// 必須額外傳遞長度
void print_array(int *arr, size_t len) { ... }

// 字串慣例:以 '\0' 結尾,無需傳長度
void print_str(const char *str) { ... }

指標陣列 vs 陣列指標 vs 二維陣列

int *ptr_array[3];        // 指標陣列:3個 int* 元素
int (*arr_ptr)[3];        // 陣列指標:指向含3個int的陣列
int matrix[2][3];         // 二維陣列:連續儲存 2*3 個 int

// 二維陣列記憶體佈局:行優先
int matrix[2][3] = {{1,2,3},{4,5,6}};
// 記憶體:1 2 3 4 5 6
// &matrix[0] = 0x1000, &matrix[1] = 0x100C (差12 bytes = 3*sizeof(int))

多維陣列函數參數

// 必須指定除第一維外的所有維度
void print_2d(int arr[][3], int rows);        // OK
void print_2d(int (*arr)[3], int rows);       // 等價寫法

// 三維陣列
void print_3d(int (*arr)[2][4], int depth);   // arr[depth][2][4]

動態分配二維陣列:兩種策略

策略一:單一連續區塊 + 手動索引計算

int rows = 3, cols = 5;
int *matrix = malloc(rows * cols * sizeof(int));
matrix[i * cols + j] = value;  // 手動計算位移

策略二:指標陣列 + 連續資料區

int **matrix = malloc(rows * sizeof(int*));
matrix[0] = malloc(rows * cols * sizeof(int));
for (int i = 1; i < rows; i++) {
    matrix[i] = matrix[0] + i * cols;  // 設定各行起始位址
}
// 使用 matrix[i][j] 自然語法存取

不規則陣列 (Jagged Array)

// 複合字面量初始化 (C99)
int *jagged[3] = {
    (int[]){100},
    (int[]){10, 20, 30},
    (int[]){1, 2, 3, 4, 5}
};
// 每行長度不同,存取需額外維護長度資訊

記憶體管理黃金法則

  1. 誰分配誰釋放:malloc/realloc 配對 free
  2. 釋放後置 NULL:防止野指標重複釋放
  3. 避免回傳區域變數位址:堆疊記憶體函數返回即失效
  4. Valgrind 定期檢測:valgrind --leak-check=full ./program

深入理解指標與陣列的記憶體語義,是寫出高效、安全 C 程式的關鍵。建議配合圖解記憶體佈局、GDB 觀察執行時狀態、閱讀開源專案原始碼,逐步建立直覺性掌握。

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