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

C 語言字符串字面量 vs 字符數組:char *p vs char p[] 內存佈局、可修改性與 sizeof 差異深度解析

     編輯:關於C語言

一、核心差異一覽

特性char *p = "123";char p[] = "123";
存儲位置字符串常量在 .rodata 段 (唯讀),指針 p 在棧/數據段字符數組在 棧 (局部) 或 .data/.bss (全局),內容可寫
可修改性不可修改內容 (*p = 'x' → 段錯誤),指針可改可修改內容 (p[0] = 'x' 合法)
sizeof指針大小 (4/8 字節)數組長度含結束符 4 (含 \0)
賦值語義指針指向常量區地址編譯器生成代碼逐字符拷貝 (strcpy 效果)
類型char* (實為 const char*)char[4] (退化為 char* 時失去長度信息)

二、內存佈局圖解

// char *p = "123";
棧/數據段:  p  ──────► .rodata 段:  '1' '2' '3' '\0'  (唯讀)

// char p[] = "123";
棧/數據段:  p[0]='1', p[1]='2', p[2]='3', p[3]='\0'  (可讀寫)

三、代碼驗證實驗


#include 
#include 

int main() {
    char *p1 = "abcdef";
    char p2[] = "abcdef";

    printf("sizeof(p1)=%zu  sizeof(p2)=%zu\n", sizeof(p1), sizeof(p2));
    // 64位輸出: sizeof(p1)=8  sizeof(p2)=7

    // p1[0] = 'g'; // 運行時崩潰:Segmentation fault (寫唯讀段)
    ++p1;           // 合法:修改指針本身
    printf("p1 now: %s\n", p1); // "bcdef"

    p2[0] = 'g';    // 合法:修改數組內容
    printf("p2 now: %s\n", p2); // "gbcdef"

    return 0;
}

四、函數參數傳遞陷阱


void Func1(char *str)  { str[0] = 'X'; } // 若傳字符串常量 → 崩潰
void Func2(char str[]) { str[0] = 'X'; } // 同義,退化為指針

// 安全調用
char buf[] = "hello";
Func1(buf); // OK
Func1("hello"); // 崩潰!

// 推薦簽名:明確只讀意圖
void SafeFunc(const char *str); // 編譯器會檢查傳入字符串常量合法,傳數組也合法

五、進階場景:多維與指針數組


// 指針數組:每個元素指向字符串常量
char *arr1[] = {"one", "two", "three"}; // arr1 在棧,指向 .rodata

// 二維數組:連續存儲,可修改
char arr2[][10] = {"one", "two", "three"}; // 每行 10 字節,含 \0

// sizeof 對比
sizeof(arr1); // 3 * sizeof(char*) = 24 (64位)
sizeof(arr2); // 3 * 10 = 30

六、最佳實踐原則

  1. 只讀字符串:統一用 const char* p = "..." 或 const char p[] = "...",編譯器強制保護。
  2. 需修改/構建字符串:用字符數組 char buf[SIZE] 或動態分配 malloc/new。
  3. 函數參數:輸入字符串用 const char*,輸出緩衝區用 char* buf, size_t len。
  4. 字符串字面量合併:編譯器可能合併相同字面量("abc" == "abc" 可能為真),切勿依賴地址唯一性。
  5. C++ 偏好 std::string/std::string_view:自動管理內存、避免指針語義陷阱。

七、總結

char *p = "..." 是指向唯讀內存的指針,char p[] = "..." 是可修改的字符數組副本。搞清存儲段、可修改性、sizeof 語義、函數參數退化,是避免段錯誤、邏輯 Bug、安全漏洞的關鍵。

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