| 場景 | 無指針(值傳遞) | 有指針(地址傳遞) |
| 大數據傳遞 | 拷貝整個結構體,開銷大 | 傳遞 8 字節地址,極低開銷 |
| 函數修改參數 | 修改副本,原值不變 | 修改原內存,調用者可見 |
| 多模塊共享數據 | 各持副本,一致性難保證 | 共享同一內存,實時同步 |
| 動態內存管理 | 無法實現 | malloc/free 核心依賴 |
二、指針基礎語法
1. 獲取地址:& 運算符
int x = 5;
printf("x lives at %p\n", &x); // %p 以十六進制打印地址
// 輸出示例:x lives at 0x7ffd1234567c
2. 定義指針變量
int *address_of_x = &x; // 類型:int*(指向 int 的指針)
int* 是類型,「指向 int 的指針」
address_of_x 存儲地址值 &x
3. 解引用:* 運算符(間接訪問)
int value = *address_of_x; // 獲取地址指向的值 → 5
*address_of_x = 10; // 修改地址指向的內存 → x 變為 10
printf("After change, x = %d\n", x); // 輸出 10
三、指針與函數參數:實現「引用傳遞」
案例:船長導航(修改經緯度)
#include
// 函數接收指針,修改原變量
void go_south_east(int *lat, int *lon) {
*lat = *lat - 1; // 緯度 -1(向南)
*lon = *lon + 1; // 經度 +1(向東)
}
int main() {
int latitude = 32;
int longitude = -64;
printf("起始位置: [%d, %d]\n", latitude, longitude);
// 傳遞地址
go_south_east(&latitude, &longitude);
printf("當前位置: [%d, %d]\n", latitude, longitude);
// 輸出:當前位置: [31, -63]
return 0;
}
關鍵對比
// 錯誤:值傳遞,無法修改原變量
void bad_south_east(int lat, int lon) {
lat = lat - 1;
lon = lon + 1;
}
// 正確:地址傳遞,修改原變量
void good_south_east(int *lat, int *lon) {
*lat = *lat - 1;
*lon = *lon + 1;
}
四、指針圖解:內存視角
調用前 main 棧幀: go_south_east 棧幀:
┌──────────────┐ ┌──────────────┐
│ latitude: 32 │ │ lat: 0x7ffc... │ ← &latitude
│ longitude:-64│ │ lon: 0x7ffc... │ ← &longitude
└──────────────┘ └──────────────┘
│ │
│ 传递地址 │ 解引用修改
▼ ▼
┌──────────────┐ ┌──────────────┐
│ latitude: 31 │ ← 修改生效 │ *lat = 31 │
│ longitude:-63│ ← 修改生效 │ *lon = -63 │
└──────────────┘ └──────────────┘
五、常見指針聲明模式
| 聲明 | 含義 | 示例 |
int *p; | 指向 int 的指針 | int x; p=&x; |
int *p, *q; | 兩個指向 int 的指針 | int *p=&x, *q=&y; |
int *p, q; | p是指針,q是int | ⚠️ 易誤讀,建議分行 |
const int *p; | 指向常量 int 的指針(只讀) | p=&x; *p=10; // 錯誤 |
int *const p; | 常量指針(地址不可變) | p=&x; p=&y; // 錯誤 |
const int *const p; | 常量指針指向常量 | 雙重只讀 |
六、指針安全準則
- 初始化:定義即初始化
int *p = NULL; 或 int *p = &x;
- 檢查:解引用前檢查
if (p != NULL)
- 釋放後置空:
free(p); p = NULL; 防野指針
- 不越界:數組訪問確保索引合法
- 類型匹配:
int* 不直接指向 float(需強轉且謹慎)
七、調試技巧:打印指針與值
int x = 42;
int *p = &x;
printf("p = %p (地址值)\n", (void*)p);
printf("&x = %p (同地址)\n", (void*)&x);
printf("*p = %d (解引用值)\n", *p);
printf("x = %d (原變量值)\n", x);
printf("&p = %p (指針變量自身地址)\n", (void*)&p);
八、本節作業
- 編寫
swap(int *a, int *b) 交換兩整數值
- 編寫
min_max(int arr[], int n, int *min, int *max) 通過指針返回最值
- 實驗:
int *p; *p = 10; 觀察崩潰(野指針)
- 閱讀
man 3 malloc 理解動態內存分配返回指針
總結
指針 = 內存地址 + 類型信息。核心操作:& 取址,* 解引用。函數參數用指針實現「引用語義」,是 C 語言模塊化、高性能、系統級編程的基石。下一節將探討數組與指針的深度關係。
- 上一篇文章: C語言入門教程(二):變量、輸入輸出與第一個完整交互程序
- 下一篇文章: 深入理解 PHP 內核(七):變量與資料類型——常量實現詳解
Copyright ©
程式碼之家 All Rights Reserved