指針是 C 語言的靈魂,也是初學者最大的攔路虎。本文系統梳理指針定義、運算、函數參數傳遞、陣列關係等核心知識點,配合完整可編譯代碼範例,助你建立清晰的指針心智模型。
類型標識符 *指針變量名;
// 例
int *pa, *pb; // pa、pb 均為 int*
float *q; // q 為 float*
關鍵:* 屬於類型聲明一部分,變量名是 pa 而非 *pa。
int n1, n2;
int *p1, *p2, *p3;
p1 = &n1; // 取址賦值
p2 = &n2;
p3 = p2; // 指針間賦值(共享指向)
類型匹配原則:指針類型必須與目標變量類型一致,void* 為通用指針可接收任意類型位址。
pi = &x;
x = 1;
y = *pi + 9; // 等價於 y = x + 9
*pi 與 x 成為同一記憶體單元的別名,修改任一者即修改該單元值。
p++ / p--:按所指類型大小移動位址(如 int* 移 4 位元組)。p + n:向後偏移 n 個元素位置。int a = 10, *p = &a;
*p++ // 等價 *(p++):取值後 p 移向下一個 int
(*p)++ // 等價 ++(*p):a 變為 11,p 不動
*p+1 // 等價 (*p)+1:值為 11,不修改 a
== != < > <= >=),高位址大於低位址。ptrdiff_t,值為元素個數差(位址差 / sizeof(類型))。NULL (0) 比較判斷空指針。void fun(int num) { num = 20; } // 傳值:不影響實參
void fun(int *p) { *p = 20; } // 傳址:修改實參指向的值
// ❌ 1. 傳值:僅交換形參副本
void swap1(int x, int y) { int t=x; x=y; y=t; }
// ❌ 2. 傳指針但交換指針本身:僅交換區域指針變量
void swap2(int *p1, int *p2) { int *t=p1; p1=p2; p2=t; }
// ✅ 3. 傳指針並交換指向的內容:真正實現交換
void swap3(int *p1, int *p2) { int t=*p1; *p1=*p2; *p2=t; }
int a[5], *p = a; // p 指向 a[0]
int *q = &a[3]; // q 指向 a[3]
// 索引法
for (i=0; i<10; i++) scanf("%d", pa+i), printf("%d ", *(pa+i));
// 指針法(更高效,編譯器易優化)
for (pa = arr; pa < arr+10; pa++) scanf("%d", pa);
for (pa = arr; pa < arr+10; pa++) printf("%d ", *pa);
int a[10], *p, count = 0;
for (p = a; p < a+10; p++)
if (*p > 0) { count++; printf("%d ", *p); }
陣列參數退化為指針,實際傳遞首元素位址(地址傳遞),函數內修改陣列元素影響原陣列。
void input(int a[10], int n) { for(i=0;i
int main() {
int a=10,b=30,*p1=&a,*p2=&b;
printf("%d %d %d %d %p %p %p %p\n",a,b,*p1,*p2,p1,p2,&p1,&p2);
a++; (*p2)++;
printf("%d %d %d %d %p %p %p %p\n",a,b,*p1,*p2,p1,p2,&p1,&p2);
*p1++; *p2--; // 注意優先級:*p1++ 等價 *(p1++)
printf("%d %d %d %d %p %p %p %p\n",a,b,*p1,*p2,p1,p2,&p1,&p2);
printf("%td %td\n", p1-p2, p2-p1); // 指針減法
}
指針變量本身 (位址) 與 指向的值 (解引用)& 取址、* 解引用、++/-- 移動元素NULL 檢查習慣指針不是魔法,而是記憶體位址的直接操作介面。畫圖(方框表記憶體、箭頭表指向)是練就指針直覺的最佳方法。