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

C語言字符數組與字符指針數組深度解析:內存佈局與訪問差異

     編輯:C 語言入門

代碼示例


#include 

int main() {
    // 1. 二維字符數組:連續內存塊,每行固定 4 字節
    char strs[3][4] = {"123", "abc", "edf"};
    // 內存佈局:
    // strs[0]: '1','2','3','\0', (可能有填充)
    // strs[1]: 'a','b','c','\0'
    // strs[2]: 'e','d','f','\0'

    // 2. 字符指針數組:存儲 3 個指針(各 8 字節於 64 位系統)
    char *ptr_arr[3];

    // 3. 指向指針的指針
    char **pp;

    // 4. 建立映射:指針數組指向二維數組各行
    for (int i = 0; i < 3; i++)
        ptr_arr[i] = strs[i];  // strs[i] 退化為 char* (行首地址)

    pp = ptr_arr;  // pp 指向指針數組首元素

    // 5. 遍歷輸出
    for (int i = 0; i < 3; i++)
        puts(*pp++);  // *pp 獲取 char*,遞增 pp

    return 0;
}

內存模型對比圖解

char strs[3][4] (二維數組)          char *ptr_arr[3] (指針數組)
┌─────────────────────────┐         ┌─────────────────────────┐
│ strs[0] │ '1' '2' '3' '\0' │         │ ptr_arr[0] │ ──────────────┐
├─────────────────────────┤         ├─────────────────────────┤     │
│ strs[1] │ 'a' 'b' 'c' '\0' │         │ ptr_arr[1] │ ──────────────┼──▶ 各行數據
├─────────────────────────┤         ├─────────────────────────┤     │
│ strs[2] │ 'e' 'd' 'f' '\0' │         │ ptr_arr[2] │ ──────────────┘
└─────────────────────────┘         └─────────────────────────┘
連續 3×4=12 字節                      3×8=24 字節 (64位) 存地址

關鍵差異總結表

特性二維字符數組 char a[M][N]字符指針數組 char *a[M]
內存佈局連續塊,行主序指針數組 + 分散的字符串
行長度固定 N (含\0)可變(每行指向不同長度字符串)
修改內容直接修改 a[i][j]修改指向的字符串(若指向字面量則不可修改)
賦值/複製需 strcpy 逐行直接賦值指針 a[i] = "new"
sizeofM*NM*sizeof(char*)
參數傳遞退化為 char (*)[N]退化為 char **

經典面試題:參數傳遞與 sizeof


void func1(char a[3][4]) {
    // a 類型:char (*)[4] (指向 4-char 數組的指針)
    printf("%zu\n", sizeof(a));  // 8 (指針大小),非 12!
}

void func2(char *a[3]) {
    // a 類型:char **
    printf("%zu\n", sizeof(a));  // 8
}

int main() {
    char strs[3][4] = {"123","abc","edf"};
    char *ptrs[3] = {"123","abc","edf"};  // 指向字面量

    printf("main sizeof(strs)=%zu\n", sizeof(strs));  // 12
    printf("main sizeof(ptrs)=%zu\n", sizeof(ptrs)); // 24 (64位)

    func1(strs);  // 退化為指針,sizeof 失效
    func2(ptrs);
}

動態分配對比

二維數組動態分配(連續內存)


// 真正的連續二維數組
char (*matrix)[4] = malloc(3 * sizeof(*matrix));  // 3 行,每行 4 char
strcpy(matrix[0], "123");
// 釋放:free(matrix);

指針數組動態分配(不連續)


char **matrix = malloc(3 * sizeof(char*));
for (int i = 0; i < 3; i++)
    matrix[i] = strdup("dynamic");  // 每行獨立分配
// 釋放:逐行 free(matrix[i]),再 free(matrix)

實際選型指南

場景推薦理由
固定長度字符串集合(如命令表、錯誤碼)二維數組緊湊、連續、缓存友好、無碎片
可變長度字符串(如參數解析、配置項)指針數組靈活、易擴展、支持字面量直接賦值
需頻繁增刪字符串指針數組 + 動態分配避免大塊內存移動
高性能遍歷/拷貝連續二維數組memcpy 一次性拷貝、SIMD 友好

總結

char a[M][N] 是連續內存塊,行長固定;char *a[M] 是指針集合,指向分散字符串。理解內存佈局、退化規則、sizeof 行為、修改權限(字面量只讀)的差異,是 C 語言字符串處理進階的分水嶺。根據數據特性(固定/可變長、靜態/動態)選擇合適結構,能顯著提升代碼清晰度與性能。

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