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

C 語言深度解析:char * 與字符數組的本質區別

     編輯:關於C語言

C 語言深度解析:char * 與字符數組的本質區別

許多 C 語言學習者混淆 `char *`(字符指針)與 `char[]`(字符數組)。本文從內存模型、指針算術、字符串處理函數約定三個維度,徹底釐清二者的本質區別與聯繫。

核心結論先行

  • char[] 是數組:擁有連續內存空間,存儲字符序列,數組名是首元素地址常量(不可修改指向)。
  • char * 是指針:只存儲一個地址,指向某塊內存(可能是數組、堆內存、字符串字面量)。指針變量本身可修改指向。
  • 字符串是約定:C 語言無字符串類型,約定「以 '\0' 結尾的字符序列」為字符串。`printf`、`strlen` 等函數要求傳入符合此約定的 `char *`。

內存模型對比

字符數組 `char str[] = "hello";`

棧內存布局:
地址:  0x7ffe...  0x7ffe...+1  0x7ffe...+2  0x7ffe...+3  0x7ffe...+4  0x7ffe...+5
內容:    'h'         'e'          'l'          'l'          'o'          '\0'
str   →  首元素地址(常量,不可修改)
sizeof(str) = 6

數組在棧上分配 6 字節,內容可修改(`str[0] = 'H'` 合法)。

字符指針 `char *p = "hello";`

棧內存:          只讀數據段(.rodata):
p (8字節)  ──────→  'h' 'e' 'l' 'l' 'o' '\0'
sizeof(p) = 8 (64位系統)

指針 `p` 在棧上,指向只讀段的字符串字面量。**嘗試修改 `p[0] = 'H'` 導致未定義行為(通常崩潰)。**

動態分配 `char *p = malloc(6); strcpy(p, "hello");`

指針指向堆內存,內容可修改,用完需 `free(p)`。

指針算術差異

int arr[5] = {1,2,3,4,5};
int *pi = arr;
pi++;  // pi 增加 sizeof(int) 字節,指向下一個 int

char str[] = "hello";
char *pc = str;
pc++;  // pc 增加 sizeof(char) = 1 字節,指向下一個字符

指針類型決定了指針算術的步長(`sizeof(類型)`),這是類型系統賦予指針的語義。

字符串函數的「約定大於配置」

C 標準庫函數(`strlen`、`strcpy`、`printf("%s")` 等)的規約是:

參數 `char *s` 必須指向一個以 '\0' 結尾的字符序列。

函數內部只是從起始地址逐字節遍歷,直到遇到 '\0'。因此:

  • 傳入 `char[]` 合法(數組名退化為首元素地址)。
  • 傳入指向字符串字面量的 `char *` 合法。
  • 傳入指向無 '\0' 結尾的字符數組的 `char *` → **未定義行為**(越界讀取)。
  • 傳入未初始化的 `char *` → **災難**。

常見陷阱與最佳實踐

場景正確做法錯誤示例
需要修改字符串內容`char str[] = "hello";` 或 `malloc` + `strcpy``char *p = "hello"; p[0]='H';`
函數參數接收字符串`void func(const char *s)``void func(char *s)` 並嘗試修改
返回動態分配字符串文檔註明「調用者負責 free」返回棧上數組地址
字符串字面量賦值給 `const char *`賦值給 `char *`(C++ 編譯器會報錯,C 僅警告)

總結

char[] 是「有內容的容器」,char * 是「指向內容的標籤」。字符串不是類型,而是「以 '\0' 結尾」的數據協議。理解內存佈局、指針算術、庫函數約定三位一體,才能在 C 語言字符串處理中游刃有餘。

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