char* c1 = "abc"; // 指向字串常值區
char c2[] = "abc"; // 陣列在堆疊,內容可修改
char* c3 = (char*)malloc(3);
c3 = "abc"; // 錯誤!洩漏 malloc 記憶體,c3 指向常值區
執行 c1[0] = 'X'; → 存取違規(常值區唯讀)。
執行 c2[0] = 'X'; → 正常,堆疊陣列可寫。
| 區域 | 存放內容 | 生命週期 | 可寫性 |
|---|---|---|---|
| 程式碼區 | 機器指令 | 程式結束 | 唯讀 |
| 常值區 | 字串常值、"abc" | 程式結束 | 唯讀 |
| 全域/靜態區 | 全域變數、static 變數 | 程式結束 | 可讀寫 |
| 堆疊 | 區域變數、函數參數、返回位址 | 函數返回釋放 | 可讀寫 |
| 堆積 | malloc/new 配置 | 手動 free/delete | 可讀寫 |
char* p = "hello";
// p 在堆疊 (4/8 bytes)
// "hello\0" 在常值區 (6 bytes),p 指向該處
char a[] = "hello";
// a 在堆疊 (6 bytes),內容為 'h','e','l','l','o','\0'
// 無指標間接,直接操作陣列元素
char* p = "abc";
char a[] = "abc";
sizeof(p); // 4 或 8 (指標大小)
sizeof(a); // 4 (含結束符)
| 錯誤代碼 | 問題 | 修正 |
|---|---|---|
char* p = "abc"; p[0]='X'; | 嘗試修改唯讀常值區 | 改用 char p[] = "abc"; 或 strcpy 到堆積/堆疊緩衝區 |
char* p = (char*)malloc(4); p = "abc"; | 洩漏 malloc 記憶體,p 指向常值區 | strcpy(p, "abc"); 複製內容 |
void f(char* s) { s = "new"; } | 只改變區域指標副本,呼叫端不受影響 | 傳 char** 或回傳新指標,或用 std::string |
char* p = "abc"; delete p; | 刪除非 new 記憶體 → 未定義行為 | 絕對不要 delete/free 指向常值區/堆疊的指標 |
std::string 或 std::string_view(C++17),自動管理記憶體、避免指標陷阱。std::vector<char> buf(str.begin(), str.end()); buf.push_back('\0'); 取得可修改緩衝區。const:const char* p = "abc"; 編譯器會阻擋修改嘗試。char* 是指標,指向哪裡由初始化決定;char[] 是陣列,自帶儲存空間。理解記憶體五大區、常值區唯讀、指標與陣列的型別差異,是寫出健壯 C/C++ 程式的基石。