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

C語言指針核心概念:從地址到間接訪問的完整圖解

     編輯:關於C語言

指針:C 語言的靈魂與分水嶺

「不懂指針,不懂 C。」指針將內存地址提升為一級數據類型,賦予程序員對內存的直接控制權。本文從底層原理到實戰模式,構建完整指針認知體系。

一、指針與地址:兩個視角的同一實體

1. 變量在內存中的表示

  • 每個變量佔據一段連續內存區域。
  • 區域起始地址 = 變量地址。
  • 地址本質是無符號整數,但類型化地址(指針)攜帶類型信息。

2. 指針類型系統

int x = 10;
int *px = &x;     // px 類型:int* (指向 int 的指針)
                    // px 值:x 的地址 (如 0x7ffe...)

double d = 3.14;
double *pd = &d;  // pd 類型:double*,值:d 的地址

// 關鍵:px 和 pd 值可能相同(地址數值),但類型不同!
// 類型決定:解引用訪問多少字節、指針算術步長、類型安全檢查

3. 定義與初始化

int *ip;           // 未初始化,野指針 (危險)
int *ip = NULL;    // 空指針,明確無效
int i = 10;
int *ip = &i;      // 初始化為 i 的地址

// 多指針定義陷阱
int *p1, *p2;      // 兩個指針
int *p3, p4;       // p3 是指針,p4 是 int!建議一行一個。

二、間接訪問:解引用運算符 *

1. 基本機制

int i = 10, x;
int *ip = &i;

x = *ip;  // 1. 取 ip 的值 (地址) 2. 訪問該地址的 int 內容 3. 賦給 x
// 等價於 x = i;

*ip = 20; // 修改 ip 指向的內存,i 變為 20

2. 圖解內存關係

ip (地址 0x1000)          i (地址 0x2000)
+--------+                +--------+
| 0x2000 | ─────────────→ |   10   |
+--------+                +--------+

3. 指針賦值 vs 解引用賦值

int i = 'a', j = 'b';
int *p1 = &i, *p2 = &j;

p2 = p1;      // 指針賦值:p2 現在也指向 i
              // p1、p2 共享同一目標

*p2 = *p1;    // 解引用賦值:將 p1 指向的值複製到 p2 指向的位置
              // j 變為 'a',p2 仍指向 j

關鍵區別:p2=p1 改變指向;*p2=*p1 改變數據。

三、指針在表達式中的運算

1. 解引用優先級高於算術

y = *px + 5;     // (*px) + 5
y = ++*px;       // ++(*px) : 先增再用
y = *px++;       // *(px++) : 先用再增 (px 移動到下一個 int)

2. 合法指針運算

運算條件結果
ptr + nptr 指向數組元素指向第 n 個後續元素
ptr - nptr 指向數組元素指向第 n 個前序元素
ptr1 - ptr2同一數組元素距離 (ptrdiff_t)
==, !=, <, >...同一數組/對象位置比較

❌ 指針+指針、指針*指針、指針/整數 皆非法。

3. 縮放因子表

char    : 1
short/int : 2/4 (視平台)
long/float : 4/8
double  : 8
結構體  : sizeof(struct)
// 編譯器自動處理:p+1 實際地址增量 = 1 * sizeof(*p)

四、指針與 const:雙重保護


const int *p1;    // 指向常量的指針:不能通過 p1 修改數據,*p1=10 錯誤
int *const p2;    // 常量指針:p2 本身不可修改指向,p2=&x 錯誤
const int *const p3; // 雙重常量

口訣:const 在 * 左 → 數據常量;在 * 右 → 指針常量。

五、經典陷阱與最佳實踐

陷阱後果防範
使用未初始化指針隨機崩潰/數據破壞定義即初始化 (NULL 或合法地址)
釋放後不置 NULL野指針,二次釋放崩潰free(ptr); ptr = NULL;
返回局部變量地址棧內存失效,訪問垃圾用靜態/堆/輸出參數
指針越界訪問緩衝區溢出,安全漏洞邊界檢查,使用 size_t 索引
類型懲罰違規未定義行為 (嚴格別名規則)用聯合體/char*/memcpy

六、進階模式:不透明指針 (Opaque Pointer / Pimpl)


// header.h - 公開接口
struct WidgetImpl; // 前向聲明
typedef struct WidgetImpl *Widget;

Widget widget_create();
void widget_do(Widget w);
void widget_destroy(Widget w);

// source.c - 實現隱藏
struct WidgetImpl {
    int id;
    char *name;
    // 私有數據...
};

Widget widget_create() {
    Widget w = malloc(sizeof(*w));
    w->id = 0; w->name = NULL;
    return w;
}

優勢:編譯防火牆、二進制兼容、封裝實現細節。

總結

指針 = 類型化地址 + 間接訪問機制。掌握三要素:

  1. 聲明:T *p,讀法「p 是指向 T 的指針」。
  2. 賦值:p = &obj / malloc / NULL。
  3. 解引用:*p 訪問目標對象。

嚴守生命週期、邊界、const 正確性,指針將成為你手中最鋒利的編程利器。

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