| 符號 | 作左值時 | 作右值時 |
普通變量 a | 地址 &a | 數值 |
指針 p | 指針自身地址 &p | 指向的地址 p(即 *p 的地址) |
解引用 *p | 目標地址 p | 目標數值 |
數組名 arr | 非法(數組名是常量指針) | 首元素地址 &arr[0] |
字符串字面量 "hello" | 非法 | 首字符地址 |
關鍵代碼驗證
char ga[] = "abcdefghijklmn";
char *gp = "abcdefghijklmn";
printf("ga = %#x\n", ga); // 數組名作右值 → 首地址
printf("&ga = %#x\n", &ga); // 取數組名地址 → 同首地址(但類型不同)
printf("gp = %#x\n", gp); // 指針作右值 → 指向字面量的地址
printf("&gp = %#x\n", &gp); // 指針變量自身地址
void my_array_func(char ca[10]) {
printf("&ca = %#x\n", &ca); // 形參退化為指針,&ca 是棧上指針變量地址
printf("ca = %#x\n", ca); // 同實參首地址
++ca; // 合法:修改局部指針副本
}
void my_pointer_func(char *pa) {
printf("&pa = %#x\n", &pa); // 棧上指針變量地址
printf("pa = %#x\n", pa); // 同實參地址
++pa; // 合法
}
數組名 ≠ 指針:直接引用 vs 間接引用
- 數組名:編譯器知曉其地址與長度,訪問
arr[i] 直接按 base + i*sizeof(elem) 計算地址,**無需讀取指針變量**。
- 指針:運行時必須先讀取指針變量的值(地址),再解引用,**多一次間接訪問**。
跨文件聲明陷阱
// file1.c
int a[10];
// file2.c
extern int *a; // 錯誤!file2 以指針方式訪問 → 先讀地址再解引用 → 崩潰
// 正確:extern int a[]; 或 extern int a[10];
總結
- 數組名是「地址常量」,右值語境下直接代表首地址。
- 指針是「地址變量」,右值語境下代表它存儲的地址。
char *p = "str" 中,"str" 作右值提供地址賦給 p;p 自身有地址(左值)。
- 函數參數
char a[] 實際退化為 char *a,但調用時傳遞數組名仍按地址傳遞。
搞清左值/右值、直接/間接引用,指針與數組的一切「怪異行為」皆有迹可循。
- 上一篇文章: Turbo C 2.0 深度探秘(三):編譯鏈路、TLIB 庫管理與 printf 替換實戰
- 下一篇文章: IBM 上海筆試真題:C 語言實現字符串分割 split 函數
Copyright ©
程式碼之家 All Rights Reserved