首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言指標入門:從記憶體位址到指標變數的完整建模指南

     編輯:關於C語言

指標是 C 語言區別於其他高階語言的核心特性,直接對應硬體記憶體位址。本文從計算機儲存體架構出發,建立「位址→指標→指標變數」的完整心智模型,涵蓋宣告、賦值、運算子(&/*)、指標算術、陣列退化規則,並以圖解方式消除初學者最常見的困惑。

記憶體、位址與指標的物理意義

  • 記憶體:位元組陣列,每個位元組有唯一編號(位址)。
  • 位址:位元組編號,十六進位表示(如 0x7FFC1234)。
  • 指標:位址的同義詞,強調「指向某資料結構的起始位址」。
  • 指標變數:儲存位址的變數,自身佔用記憶體(32 位元 4 bytes,64 位元 8 bytes)。

比喻:銀行帳號 = 指標,存摺內容 = 資料,記錄帳號的紙條 = 指標變數。

指標變數宣告語法

類型名 *變數名;  // * 屬於宣告子,非型別一部分
int *p1;          // p1 指向 int
double *p2;       // p2 指向 double
char *p3;         // p3 指向 char
// 同行多宣告陷阱:
int *p, q;  // p 是 int*,q 是 int!建議分行寫。

指標賦值:只能存位址

int a = 10;
int *p = &a;   // 取址運算子 & 取得 a 的位址
// p = 1000;   // 錯誤:整數不能直接賦值給指標(需強制轉型)
// *p = &a;    // 錯誤:*p 是 int,不能存位址

鐵律:指標變數必須初始化後才能使用,未初始化指標(野指標)解參考會導致未定義行為。

指標運算子雙雄

運算子名稱操作數結果優先級/結合性
&取址左值(變數、陣列元素)該變數位址(常量指標)單目,右結合
*解參考/間接存取指標變數指標指向的變數(左值)單目,右結合
int a = 5, *p = &a;
printf("%d\n", *p);  // 5
*p = 20;             // 修改 a
printf("%d\n", a);   // 20

指標算術:型別感知的位址運算

指標只能進行:

  • 指標 ± 整數:p + n 移動 n * sizeof(*p) bytes。
  • 指標 - 指標:同陣列內兩指標相減得元素個數差(ptrdiff_t)。
  • 關係比較:同陣列內比較高低。

禁止:指標 + 指標、指標 × 數、指標 % 數、指標與整數比較(除 0)。

陣列遍歷的指標寫法

int a[5] = {10,20,30,40,50};
int *p = a;
while (p < a+5) {
    printf("%d ", *p);
    ++p;  // 移動 sizeof(int) bytes
}

陣列名退化規則(核心考點)

在表達式中,陣列名 a 自動轉換為 &a[0](指向首元素的指標),例外:

  1. sizeof(a) → 整個陣列大小(bytes)。
  2. &a → 指向整個陣列的指標(型別 int(*)[5])。
  3. 字串常數初始化 char a[] = "abc";。
int a[5];
printf("%p %p %p\n", a, &a[0], &a);  // 數值相同,型別不同!
// a      : int*
// &a[0]  : int*
// &a     : int(*)[5]

多維陣列退化

int a[3][4];
a        → int(*)[4]  (指向 4-int 陣列的指標)
a[0]     → int*       (指向 a[0][0])
a[i]     → int*       (指向 a[i][0])
*a       → int*       (同 a[0])

const 與指標的四種組合


const int *p1;   // 指向常數的指標:不可 *p1=...,可 p1=...
int *const p2;   // 常數指標:可 *p2=...,不可 p2=...
const int *const p3; // 完全鎖死
int const *p4;   // 同 p1(const 在 * 左邊修飾指向的型別)

口訣:* 左邊的 const 鎖指標本身,右邊的鎖指向的資料。

經典錯誤與避坑指南

錯誤程式碼問題修正
int *p; *p = 10;野指標寫入隨機位址int a; int *p = &a; *p = 10;
void f(int *p) { p = malloc(4); }修改區域副本,呼叫端不受影響void f(int **p) { *p = malloc(4); }
char *s = "hello"; s[0] = 'H';字串常數在唯讀區,寫入崩潰char s[] = "hello"; s[0] = 'H';
int a[2][3]; int *p = a;型別不匹配(int(*)[3] vs int*)int (*p)[3] = a;
free(p); p = NULL; 漏寫 p = NULL懸空指標,後續誤用養成 free(p); p = NULL; 肌肉記憶

練習題

  1. 寫出 int (*(*p)[3])(int, int) 的完整宣告含義(函式指標陣列的指標)。
  2. 實作 void swap(int *a, int *b) 並說明為何不能寫成 void swap(int a, int b)。
  3. 解釋 sizeof("abc") 與 strlen("abc") 差異。

指標不是魔法,只是「儲存位址的變數」加上「型別感知的算術」。建立正確心智模型,寫出安全、高效的 C 程式將不再困難。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved