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

C 語言指針基礎(一):指針與地址核心概念、定義、初始化、賦值與運算符

     編輯:關於C語言

前言

指針是 C 語言的靈魂,也是區分「會用 C」與「精通 C」的分水嶺。本文從計算機存儲模型出發,建立指針與地址的本質認知,系統講解指針變量定義語法、初始化規則、賦值約束、取址/取內容運算符,並揭示空指針與動態分配的關鍵細節。

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

1. 存儲模型視角

  • 變量佔用連續存儲單元(位元組),每單元有唯一**地址**(編號)。
  • 訪問變量 = 找到其地址 → 讀寫該地址內容。
  • 指針 = 變量的地址(概念上)。地址 = 指針的值(數值上)。

2. 類型系統視角

  • int x; → &x 類型是 **「指向 int 的指針」**,值是 x 的地址。
  • double d; → &d 類型是 **「指向 double 的指針」**,值是 d 的地址。
  • 雖值同為地址數值,但**類型不同** → 指針類型攜帶「所指對象類型」元信息,決定解引用大小、算術縮放、類型檢查。

3. 通俗類比:銀行帳號 vs 存款金額

  • 帳號 = 指針/地址(用於定位)。
  • 存款金額 = 存儲內容(真實數據)。
  • 指針變量 = 記錄帳號的變量,可存不同帳號(指向不同變量)。

二、指針變量定義語法

類型標識符 *變量名;  /* * 屬於聲明符一部分,非乘法 */
  • int *ip;:ip 為指向 int 的指針變量,專存 int 變量地址。
  • static int *p2;:指向靜態 int 的指針。
  • float *p3; char *p4;:分別指向 float、char。

鐵律:一個指針變量**只能指向同一類型**對象(除 void* 通用指針外)。

三、指針變量初始化與賦值

1. 初始化(定義時賦值)

int i, *ip = &i;  /* 合法:用 &i 初始化 ip */
/* 錯誤:int *ip = i;  (無 & 符) */
/* 錯誤:int *ip = *&i; (解引用結果是 int 值) */

2. 賦值語句(定義後賦值)

int i, *ip;
ip = &i;          /* 正確 */
ip = 1000;        /* 錯誤:整數不可直接賦予指針 */
*ip = &i;         /* 錯誤:左值是 int,非指針 */

3. 靜態/外部指針默認初始化

  • 未顯式初始化時 → **空指針 (NULL)**,值為 0。
  • 空指針**不指向任何有效數據**;常用作函數返回錯誤標誌(如 malloc 失敗返回 NULL)。

四、動態記憶體分配:指針的實戰舞臺

區域指針未初始化為**隨機地址**(垃圾值),直接使用極其危險。正確做法:

#include   /* 或  舊版 */

int *ip = (int*)malloc(sizeof(int));   // 分配 1 個 int
*ip = 420;                             // 解引用賦值

char *str = (char*)malloc(20);         // 分配 20 字節
strcpy(str, "Good, Answer!");          // 字符串拷貝

/* 分配陣列 */
int *arr = (int*)malloc(3 * sizeof(int));
arr[0] = 1234;  *(arr+1) = 4567;  *(arr+2) = 234;  // 下標/指針算術等價

關鍵理解:malloc 返回 void*,需**強制轉換**為目標指針類型(C++ 必須,C 隱式轉換但建議顯式)。分配後的記憶體**專屬於該指針管理**,用完必須 free 歸還。

五、指針運算符雙雄

1. 取址運算符 &

  • 單目、右結合。
  • 功能:取操作數變量的地址。&a 類型為「指向 a 類型的指針」。
  • 已在 scanf、指針初始化中大量使用。

2. 取內容/解引用運算符 *

  • 單目、右結合。
  • 功能:訪問指針所指對象的值(讀或寫)。
  • 區別:聲明中的 * 是類型修飾符(標識「這是指針」);表達式中的 * 是運算符(標識「取所指值」)。
main() {
    int a = 5, *p = &a;
    printf("%d", *p);  // 輸出 5:*p 等價於 a
}

六、指針變量允許的運算(受限集合)

  • 賦值:p = &a; p = q; p = NULL;
  • 算術:p + n、p - n、p++、p--(按元素縮放)。
  • 關係比較:== != < > <= >=(同一數組/塊內)。
  • 差值:p - q 得元素個數 (ptrdiff_t)。
  • 禁止:指針相加、指針乘除、指針位運算、指針與浮點數運算。

七、常見新手誤區速查

誤區代碼問題正確寫法
int *p; *p = 10;野指針解引用 → 崩潰int *p = malloc(...); *p = 10;
int *p = 1000;整數賦指針int *p = (int*)1000; (極少見,硬體編程)
void f(int *p) { p = malloc(4); }形參修改不影響實參void f(int **p) { *p = malloc(4); }
free(p); *p = 0;釋放後使用 (UAF)free(p); p = NULL;

總結

指針 = **帶類型的地址變量**。掌握「定義語法、&/* 對偶、初始化/賦值約束、動態分配配合、受限運算集」五大支柱,即打通了 C 語言操作記憶體的任督二脈。後續將深入指針與數組、字符串、函數、結構的深度結合,敬請期待。

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