指針是C語言的精華,也是危險之源。本文通過「小黑板」式筆記,深入講解指針含義、函數應用、數組關係、const 限定、指針運算、動態內存及二維數組指針,並給出經典陷阱與最佳實踐。
指針本質是存儲地址的變量。內存視圖示例:
地址 存儲量 存儲值 F1 a(int) 10 F2 b(int*) F1 (a的地址)
鐵律:指針變量必須初始化。未初始化指針指向隨機地址,解引用可能破壞系統數據,導致崩潰或難以排查的Bug。
void swap(int *a, int *b) {
int t = *a; *a = *b; *b = t;
}
int div(int a, int b, int *result) {
if (b == 0) return 0; // 失敗
*result = a / b;
return 1; // 成功
}
arr 是首元素地址常量(相當於 &arr[0]),不可修改。int arr[]、int *arr、int arr[10] 完全等價,均退化為指針。p+1 指向下一個元素,*(p+1) 等價於 arr[1]。const 與指針的組合(高頻面試題)| 聲明 | 含義 | 可修改指針? | 可修改指向值? |
|---|---|---|---|
int *const p = &i; | 常量指針(指針本身不可變) | 否 | 是 (*p = 20) |
const int *p = &i; | 指向常量的指針(不可通過指針修改值) | 是 | 否 |
int const *p = &i; | 同上(const 在 * 左側) | 是 | 否 |
const int *const p = &i; | 雙重常量 | 否 | 否 |
口訣:const 在 * 右邊 → 指針不可改;在左邊 → 指向值不可改。
實戰用法:函數參數加 const 保護數組不被修改:void print(const int *arr, int n)。
p++ 移動 sizeof(*p) 字節。*p++ 解析:等價 *(p++),先取值再移動指針。> < < == !=。void * 通用指針與動態內存void * 可指向任意類型數據,但不能直接解引用,需轉型後使用。int *arr = (int*)malloc(n * sizeof(int));
if (!arr) exit(1); // 必須檢查
// 使用...
free(arr); // 必須釋放,防止內存洩漏
arr = NULL; // 防止野指針
char a[3][4] 在內存中連續存儲。a 是數組指針(指向含4個char的數組),類型為 char (*)[4]。
char **p = (char**)a; // 錯誤!類型不匹配 char (*p)[4] = a; // 正確:p 指向第一行 p+1 指向第二行 *(*p+1) 即 a[0][1]
動態分配二維數組常用「指針數組」或「單塊內存+指針運算」。
int *p, q; 只有 p 是指針,q 是 int。寫成 int *p, *q;。p = malloc(...))不影響外部,需傳二級指針或返回指針。NULL,導致野指針。指針雖難,但掌握「地址+類型」雙維認知,配合嚴格的初始化、邊界檢查、釋放置空習慣,即可馴服這把雙刃劍,寫出高效健壯的C代碼。