所有字符串字面量(如 "hello")均存放在靜態存儲區(只讀數據段),程序啟動時分配,運行期間一直存在,進程結束才釋放。這是編譯器為了效率與安全(防止誤修改)做出的設計。
| 類別 | 存儲區 | 生命週期 | 備註 |
|---|---|---|---|
| 局部變量(非 static) | 棧 | 作用域結束自動釋放 | 函數參數、函數內定義變量 |
| 全局變量、static 變量 | 靜態存儲區 | 程序全周期 | 僅初始化一次 |
| malloc/new 分配 | 堆 | 手動 free/delete 釋放 | 動態內存管理 |
| 字符串常量 | 靜態存儲區(只讀) | 程序全周期 | 全程序唯一拷貝,不可修改 |
[cpp]
char *returnStr_ok() {
char *p = "hello world!"; // p 在棧,指向靜態區的字面量
return p; // 返回靜態區地址,安全
}
[cpp]
char *returnStr_err() {
char p[] = "hello world!"; // 數組在棧,內容從靜態區拷貝而來
return p; // 返回棧地址,函數返回後棟桟幀銷毀 → 野指針
}
[cpp]
char *returnStr_fixed() {
static char p[] = "hello world!"; // static 讓數組放入靜態區
return p; // 安全返回
}
[cpp]
#include
char *s1() { // 返回局部數組
char *p1 = "qqq";
char p[] = "Hello world!";
char *p2 = "w";
printf("in s1 p=%p (stack)\n", p);
printf("in s1 literal addr=%p (static)\n", &("Hello world!"));
return p;
}
char *s2() { // 返回字面量指針
char *q = "Hello world!";
printf("in s2 q=%p (static)\n", q);
printf("in s2 literal addr=%p (static)\n", &("Hello world!"));
return q;
}
char *s3() { // 返回 static 數組
static char r[] = "Hello world!";
printf("in s3 r=%p (static)\n", r);
printf("in s3 literal addr=%p (static)\n", &("Hello world!"));
return r;
}
int main() {
char *t1 = s1(), *t2 = s2(), *t3 = s3();
printf("main: t1=%p t2=%p t3=%p\n", t1, t2, t3);
printf("%s\n%s\n%s\n", t1, t2, t3); // t1 輸出亂碼,t2/t3 正常
return 0;
}
in s1 p=0013FF0C (stack)
in s1 literal addr=00431074 (static)
in s2 q=00431074 (static)
in s2 literal addr=00431074 (static)
in s3 r=00434DC0 (static)
in s3 literal addr=00431074 (static)
main: t1=0013FF0C t2=00431074 t3=00434DC0
Hello world! ← t2 正常
Hello world! ← t3 正常
亂碼 ← t1 已成野指針
s1 中的局部數組 p 地址(棧)與字面量地址(靜態區)不同,證明發生了拷貝。s2 直接返回字面量地址,q 與 &("Hello world!") 完全一致。s3 的 static 數組 r 也在靜態區,但與字面量地址不同(編譯器為 static 數組單獨分配空間)。'a' 的 sizeof在 C 中,'a' 的類型是 int,因此 sizeof('a') == sizeof(int)(通常為 4)。C++ 中則為 char,大小為 1。
static 數組 / malloc 動態內存static 局部數組指針char buf[] = "init";(棧)或 malloc(堆)。.rodata 節區以節省 RAM。