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

C語言指針、數組與函數:本質區別、退化規則、多維動態結構完全指南

     編輯:關於C語言

核心本質區別

特性指針數組
本質存儲地址的復合類型一系列連續變量的集合
內存佈局指針變量(4/8B) + 可指向任意塊固定大小連續塊,名字綁定首地址
可變性指向目標可隨時改變地址與容量生命期內不變
典型用途動態內存、間接訪問靜態存儲、編譯時確定大小

數組作函數參數:自動退化為指針


void func(int arr[10]);      // 等價於
void func(int *arr);         // 編譯器內部按此處理
void func(int arr[]);        // 同樣退化

函數內部 sizeof(arr) 返回指針大小,**非**數組大小。若需保留大小信息,須額外傳遞長度參數或使用結構體封裝。

經典誤區:char a[] vs char *a


char a[] = "Hi, pig!";   // 數組:棧上分配 9 字節(含\0),內容可改
char *p = "Hi, pig!";    // 指針:指向只讀數據段字面量,內容不可改

內存佈局對比

// 數組 a
棧內存: [H][i][,][ ][p][i][g][!][\0]  ← 9 字節,a 標識此塊

// 指針 p
棧內存: [地址值]  ← 4/8 字節,p 存儲地址
只讀數據段: [H][i][,][ ][p][i][g][!][\0]

訪問 a[2] vs p[2] 產生的機器碼不同

  • a[2]:基址 a + 偏移 2 → 直接取值
  • p[2]:取 p 存儲的地址 + 偏移 2 → 間接取值

數組指針:指向整個數組的指針

聲明語法


int (*pElement)[2];  // 指向「含 2 個 int 的數組」的指針

應用:二維數組行指針


int array[2][3] = {{1,2,3},{4,5,6}};
int (*pa)[3] = &array[0];  // pa 指向第 0 行(含 3 個 int)

printf("%d", (*pa)[0]);  // 1 → array[0][0]
pa++;                    // 步長 = sizeof(int[3]) = 12 字節
printf("%d", (*pa)[0]);  // 4 → array[1][0]

關鍵點:指針運算步長由指向類型大小決定,pa++ 跳過整行。

指針數組:每個元素是指針的數組


struct UT_TEST_STRUCT *pTo[2][MAX_NUM];  // 二維指針數組

兩大優勢

  1. 動態分配內容:各指針可指向不同大小塊,避免靜態二維數組浪費空間
  2. 索引便利:pTo[i][j] 直接雙下標訪問

指向指針的指針:動態二維數組/文本行存儲

文本編輯器行存儲模型


char **ppText = NULL;      // 行指針數組(縱向動態)
char *pCurrText = NULL;    // 當前行內容(橫向動態)
ULONG ulCurrLines = 0, ulAllocedLines = 0;

while (pCurrText = getline(pFile)) {
    if (ulCurrLines >= ulAllocedLines) {
        ulAllocedLines += 50;
        ppText = realloc(ppText, ulAllocedLines * sizeof(char *));
        if (!ppText) return;
    }
    ppText[ulCurrLines++] = pCurrText;  // 橫向:指向不定長字符串
}
  • 縱向:realloc 擴展行指針數組
  • 橫向:每行指向獨立 malloc 的字符串
  • 實現真正的雙向動態

多維數組選型決策表

場景結構聲明示例
各維度固定、總量小多維靜態數組int a[10][40]
低維固定、高維動態數組指針int (*a)[40] → a = malloc(x * sizeof(int[40]))
高維固定、低維動態指針數組int *a[10] → 每行 malloc(y * sizeof(int))
高維、低維均動態指向指針的指針int **a → 雙重 malloc

數組名細節:a vs &a


int a[2] = {1,2};
int *p = a;       // p 指向 a[0],類型 int *
p = &a;           // ❌ 編譯錯誤:&a 類型是 int (*)[2](指向整個數組的指針)
  • a / &a[0]:類型 int *,值相同
  • &a:類型 int (*)[2],值相同但類型不同
  • 建議:需要首地址時用 &a[0],語義最清晰

函數指針 vs 指針函數

聲明名稱含義
int *pF1();指針函數返回 int * 的函數
int (*pF2)();函數指針指向「無參返回 int 函數」的指針

括號優先級改變語義:() 高於 *。

總結

指針、數組、函數三者交織構成 C 語言最核心的類型系統。理解退化規則、類型語義差異、指針運算步長、多維動態結構選型,是寫出高效、正確、可維護 C 代碼的必經之路。

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