首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

C 語言字符串常量與字符數組本質區別:為何 char *s = "test" 不可修改而 char s[] = "test" 可修改

     編輯:程式設計疑難解答

C 語言字符串存儲機制深度解析:字面量常量區 vs 棧區數組的生死對決

初學者常困惑:同樣是 "test",為何 char *s = "test"; s[1] = 'E'; 崩潰,而 char s[] = "test"; s[1] = 'E'; 正常?本文從編譯器、鏈接器、運行時內存佈局三個層面徹底講透這一核心知識點。

現象對比

// 情況 1:字符串字面量指針
char *s1 = "test";
s1[1] = 'E';  // 💥 段錯誤 / 訪問違例

// 情況 2:字符數組初始化
char s2[] = "test";
s2[1] = 'E';  // ✅ 正常,s2 變為 "tEst"

內存佈局本質區別

特性char *s = "test"char s[] = "test"
存儲區域只讀數據段 (.rodata / .text)棧區 (函數棧幀)
內存屬性只讀 (Read-Only),硬件級保護讀寫 (Read-Write)
生命週期程序全周期,啟動時加載函數調用期間,棧幀銷毀時釋放
變量本質s 是指針 (8/4 字節),指向常量區s 是數組 (5 字節含 \0),數據在棧上
sizeof 结果指針大小 (8/4)數組長度 (5)

編譯器與鏈接器視角

  • 字面量合並:編譯器優化,相同字符串字面量在只讀區僅存一份。char *a = "test"; char *b = "test"; 可能 a == b。
  • 數組獨立副本:每次進入作用域,編譯器生成代碼將 "test" 字節逐個拷貝到棧上分配的數組空間,互不干擾。
  • 常量傳播:優化級別高時,編譯器可能直接將 s1[1] 替換為常量 'e',但寫入操作仍觸發硬件異常。

最佳實踐準則

  1. 只讀訪問用指針:const char *s = "test"; 加 const 讓編譯器攔截寫入嘗試。
  2. 需修改用數組:char s[] = "test"; 或動態分配 char *s = strdup("test"); (記得 free)。
  3. 函數參數:接收字符串參數統一用 const char *,內部需修改則拷貝副本。

進階驗證實驗

#include 
int main() {
    char *s1 = "test";
    char s2[] = "test";
    
    printf("s1 addr: %p (rodata)\n", (void*)s1);
    printf("s2 addr: %p (stack)\n", (void*)s2);
    printf("sizeof(s1)=%zu, sizeof(s2)=%zu\n", sizeof(s1), sizeof(s2));
    
    // 驗證字面量合並
    char *s3 = "test";
    printf("s1==s3? %s\n", s1==s3 ? "yes (merged)" : "no");
    
    return 0;
}

輸出將直觀展示地址差異、大小差異、字面量合並行為。

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