指針變量聲明後必須初始化才能安全使用。初始化方式有三種:
malloc())
int *i = 7899; // ⚠️ 危險:直接指向固定地址 7899 (除非內存映射硬件)
float *f = 3.1415926; // ❌ 錯誤:將浮點常量值作為地址
char *s = "Good"; // ✅ 正確:字符串常量 "Good\0" 存儲在只讀區,s 指向首字符 'G'
關鍵區別:
int *i = 7899 將 i 指向絕對地址 0x1ED3,**極度危險**,除非做設備驅動。char *s = "Good" 讓 s 指向字符串字面量首地址,**合法且常用**。字符串常量自動添加 \0,存儲在只讀數據段,不可修改內容。
int a = 100;
int *ptr = &a; // ✅ 取變量地址賦給指針
ptr = NULL; // ✅ 空指針,表示不指向任何對象
ptr = 0; // ✅ 等價 NULL (C標準保證)
int a, m;
float n;
a = 100;
m = 20;
n = a * m * 0.1; // 隱式類型提升:int→float 運算
// 連續賦值 (Turbo C 2.0 支持)
int x, y, z;
x = y = z = 0; // 右結合:z=0 → y=0 → x=0
char c0, c1, c2;
c0 = 'b'; // 字符字面量
c1 = 50; // ASCII 碼值 (十進制) → '2'
c2 = '\x0D'; // 十六進制轉義序列 → 回車符 (CR)
int *pi;
char *ps;
*pi = 100; // ❌ 錯誤:pi 未初始化,解引用野指針!
pi = malloc(sizeof(int)); // ✅ 先分配內存
*pi = 100; // ✅ 現在安全:向分配區寫入 100
ps = "Good"; // ✅ 指向字符串常量
// *ps = 'g'; // ❌ 運行時錯誤:嘗試修改只讀內存
char *s = "Good" 內存模型
編譯階段:
1. 在目標文件 .rodata 段分配 5 字節:'G' 'o' 'o' 'd' '\0'
2. 記錄該字符串首地址 (假設 0x00402000)
運行階段:
3. 將地址 0x00402000 賦給變量 s
4. s 指向 'G',s[1]='o',s[4]='\0'
內存圖:
s (棧上) → 0x00402000 (只讀數據段)
↓
['G']['o']['o']['d']['\0']
| # | 錯誤代碼 | 問題 | 修正 |
|---|---|---|---|
| 1 | int *p; *p = 10; | 野指針解引用 | 先 p = &var 或 malloc |
| 2 | char *s = "abc"; s[0] = 'x'; | 修改只讀內存 | 用 char s[] = "abc"; (數組在棧上可修改) |
| 3 | int *p = 100; | 整數作地址 | int *p = &var; 或 malloc |
| 4 | free(p); *p = 1; | 使用後釋放 | 釋放後置 p = NULL |
| 5 | char *p = malloc(10); strcpy(p, "hello"); free(p); free(p); | 重複釋放 | 釋放後置 NULL,免費檢查 |
| 6 | int a[10]; int *p = a; p++; | 修改數組名 (常量指針) | 用臨時指針 int *q = a; q++; |
| 7 | void *vp = &i; *vp = 20; | void* 直接解引用 | *(int*)vp = 20; |
| 8 | int *p = (int*)malloc(n); // 忘檢查NULL | 分配失敗未判斷 | if(!p) return ERROR; |
| 9 | char *p = "str"; p++; | 修改指向字符串常量的指針 (指針本身可改,但易混淆) | 明確語義:const char *p = "str"; |
| 10 | int *p = &a; int *q = p; free(p); *q = 1; | 雙重釋放/懸空指針 | 明確所有權,單一釋放點 |
int *p = NULL; 或 int *p = &var;if (p) *p = val;const:const char *msg = "text"; 編譯器防誤改p vs *p掌握指針初始化與賦值的本質,是避開 C 語言「內存陷阱」的第一道防線。請反覆研讀避坑表,直到形成肌肉記憶!