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

C語言指標完整入門:定義、操作、多級指標與常見陷阱

     編輯:關於C語言

C語言指標完整入門:定義、操作、多級指標與常見陷阱

指標是 C 語言的靈魂,也是初學者最大的門檻。本文從記憶體位址觀念出發,系統講解指標定義、解引用、取址、多級指標、void 指標、空指標、常見錯誤與除錯技巧,並提供直觀圖解與可執行範例代碼。

核心觀念:指標就是「存放位址的變數」

  • 一般變數存放值:int a = 10; → 記憶體某位置存放 10
  • 指標變數存放位址:int *p = &a; → 記憶體另一位置存放 a 的位址
  • * 宣告時表「這是指標」;表達式中表「取此位址的值」(解引用)
  • & 表「取得此變數的位址」

基礎操作範例

#include <stdio.h>

int main() {
    int a = 10;        // 一般整數變數
    int *p;            // 宣告指向 int 的指標
    p = &a;            // 取得 a 的位址,存入 p

    printf("a 的值: %d\n", a);           // 10
    printf("a 的位址: %p\n", (void*)&a); // 例如 0x7ffd...
    printf("p 存放的位址: %p\n", (void*)p); // 同 &a
    printf("p 指向的值: %d\n", *p);       // 10 (解引用)

    *p = 20;           // 透過指標修改 a 的值
    printf("修改後 a: %d\n", a);          // 20

    return 0;
}

錯誤示範與修正

錯誤代碼問題修正
int *g; g = 20;指標直接賦予整數常值int val = 20; g = &val; 或 int *g = malloc(sizeof(int));
int *p; *p = 10;未初始化指標解引用(野指標)int a; int *p = &a; 或 malloc
free(p); *p = 5;釋放後繼續使用(懸空指標)free(p); p = NULL;
int *p = &localVar; return p;返回區域變數位址(棧記憶體失效)返回動態分配記憶體、靜態變數、或呼叫端提供緩衝區

多級指標圖解

int a = 100;
int *p1 = &a;       // 一級指標:指向 int
int **p2 = &p1;     // 二級指標:指向 int*
int ***p3 = &p2;    // 三級指標:指向 int**

// 記憶體佈局:
// p3 (位址) → p2 (位址) → p1 (位址) → a (值 100)

// 解引用層層遞進:
**p2 = 200;  // 等同 *p1 = 200; 等同 a = 200;
***p3 = 300; // 等同 a = 300;

void 指標(泛型指標)

  • void *ptr; 可存放任意型別位址
  • 無法直接解引用(編譯器不知大小),需強制轉型後使用
  • 常用於:泛型函數參數、記憶體分配回傳、回調函數上下文傳遞
void printInt(void *data) {
    int *p = (int*)data;  // 強制轉型
    printf("%d\n", *p);
}

void printFloat(void *data) {
    float *p = (float*)data;
    printf("%.2f\n", *p);
}

空指標

  • NULL 定義為 ((void*)0),表示「不指向任何有效物件」
  • 解引用空指標 → 未定義行為(通常 Crash)
  • 防禦性編程:if (ptr != NULL) { ... }

指標與陣列的關係

int arr[5] = {1,2,3,4,5};
int *p = arr;        // 陣列名退化為首元素位址
p[2] == *(p+2) == arr[2] == *(arr+2)  // 完全等價

// 區別:sizeof
sizeof(arr)  = 5 * sizeof(int) = 20  // 整個陣列大小
sizeof(p)    = sizeof(int*) = 8      // 指標大小 (64位系統)

函數指標

// 宣告:回傳 int,接受兩個 int 參數的函數指標
int (*funcPtr)(int, int);

int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }

funcPtr = add;
printf("%d\n", funcPtr(3, 5));  // 8

funcPtr = sub;
printf("%d\n", funcPtr(3, 5));  // -2

// 陣列:10 個函數指標
int (*funcArray[10])(int, int);

常見指標宣告對照表

宣告含義
int a;整數變數
int *a;指向整數的指標
int **a;指向指標的指標
int a[10];10 個整數的陣列
int *a[10];10 個指向整數指標的陣列
int (*a)[10];指向「10 個整數陣列」的指標
int (**a)[10];指向「指向 10 整數陣列指標」的指標
int *(*a)[10];指向「10 個整數指標陣列」的指標
int (*a)(int);指向函數的指標 (int 參數, 回傳 int)
int (*a[10])(int);10 個函數指標的陣列

除錯技巧與最佳實踐

  1. 編譯器警告全開:-Wall -Wextra -Wpedantic -Wshadow -Wconversion
  2. 靜態分析:clang --analyze、cppcheck、Coverity
  3. 執行期檢測:AddressSanitizer -fsanitize=address、Valgrind
  4. 初始化習慣:int *p = NULL; 宣告即初始化
  5. 所有權語義:明確誰負責 free,文檸化 API 契約
  6. 避免多級指標:超過二級通常設計可改進,改用結構體封裝

指標雖難,但掌握「位址、值、解引用、型別」四要素,配合畫記憶體圖、單步除錯觀察暫存器與記憶體變化,就能建立堅實的直覺。建議從基礎操作練習開始,逐步挑戰鏈表節點操作、動態二維陣列分配、函數指標回調等實戰題目。

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