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

C 語言字符串與指針深度解析:常量區、棧區與 sizeof 陷阱

     編輯:關於C

字符串字面量的存儲與生命周期

1. 編譯器自動添加結束符

代碼中以雙引號括起的字符串字面量,編譯器會自動在末尾添加 \0。"abc" 實際存儲為 "abc\0"。

2. 字符串字面量是常量嗎?—— 視上下文而定

場景代碼示例存儲位置可修改性本質
初始化字符數組char str[] = "abc";棧區(函數內)或數據段(全局)✅ 可修改數組元素逐個拷貝字面量內容
賦值給字符指針char *ptr = "abc";只讀常量區❌ 不可修改(運行時崩潰)指針指向字面量原始地址

情況一:初始化字符數組


char str[] = "abc";
// 編譯器等效展開為:
char str[4] = {'a', 'b', 'c', '\0'};
  • 定義的是數組,編譯器分配空間並拷貝內容。
  • 若在函數內部,數組在棧上;全局則在數據段。
  • str[0] = 'x'; 完全合法。

情況二:賦值給字符指針


char *ptr = "abc";
  • 定義的是指針,未分配存儲字符串的空間。
  • 編譯器將字面量放入只讀常量區(.rodata 段)。
  • ptr[0] = 'x'; 編譯通過,但運行時觸發段錯誤(寫保護內存)。
  • C++ 標準曾禁止此隱式轉換,為兼容 C 代碼才保留;強烈建議寫 const char *ptr = "abc";,編譯期即可攔截修改嘗試。

3. 指針變量本身的存儲位置


void func() {
    char *ptr = "abc";  // "abc\0" 在常量區,ptr 變量在棧上
}

指針變量 ptr 自身是局部變量,存儲在棧上;它指向的內容 在常量區。兩者存儲位置獨立。

數組類型與 sizeof 核心規則

4. 數組類型由「元素類型」+「大小」決定


char s1[3];  // 類型:char[3]
char s2[4];  // 類型:char[4]
// 雖然都是字符數組,但類型不同,不可互賦值

5. 字符串字面量類型視為常量數組


"abcdef"  // 類型視為 const char[7] (含 \0)

6. sizeof 作用於類型,非運行時求值

  • sizeof(int)、sizeof(a)(a 為 int 變量)均為 4。
  • sizeof(expr) 等價於 sizeof(type of expr),不計算表達式值。

7. 函數參數中的「數組」實為指針


void func(char sa[100], int ia[20], char *p);
// 編譯器內部等效為:
void func(char *sa, int *ia, char *p);
// 參數類型均為指針,sizeof(sa) == sizeof(ia) == sizeof(p) == 指針大小(4/8)

數組作參數退化為指針,失去大小信息。

實戰 sizeof 對比表

代碼sizeof 結果原因
char str[] = "abcdef";sizeof(str) == 7類型 char[7]
sizeof("abcdef")7字面量類型 const char[7]
char *ptr = "abcdef";sizeof(ptr) == 4/8ptr 類型 char*(指針大小)
char str2[10] = "abcdef";sizeof(str2) == 10類型 char[10],編譯期固定
函數參數 char sa[100]sizeof(sa) == 4/8退化為 char*

核心心法總結

  1. 區分「容器」與「內容」:數組是容器(可寫),字面量是內容(唯讀)。
  2. 指針指向何處,責任在程序員:指向常量區 → 唯讀;指向棧/堆數組 → 可寫。
  3. sizeof 看聲明類型,不看運行值:參數退化、數組大小固化,編譯期已定。
  4. 養成 const char * 習慣:讓編譯器幫你守護只讀內存。

徹底理解這些機制,是寫出無內存錯誤、高性能 C 代碼的基石。

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