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

C/C++ 數組地址偏移完全指南:一維與二維數組的指針算術

     編輯:關於C

核心結論先行

數組名在絕大多數表達式中退化為首元素地址,但 &arr、arr、&arr[0] 雖數值相同,類型與步長截然不同:

表達式類型+1 步長語義
&arrint (*)[N] / int (*)[M][N]整個數組大小指向整個數組的指針
arr / &arr[0]int * / int (*)[N]單元素 / 一行大小指向首元素 / 首行的指針

一維數組實測

int a[3] = {1,2,3};
// 假設 a 起始地址 0x1000,int 4 字節
&a      = 0x1000  // int (*)[3]
a        = 0x1000  // int *
&a[0]   = 0x1000  // int *

&a + 1   = 0x100C  // +12 字節 = 3*4
a + 1     = 0x1004  // +4 字節
&a[0] + 1 = 0x1004 // +4 字節

二維數組實測


int a[3][3];  // 3行3列,共36字節
// 假設起始 0x2000
&a       = 0x2000  // int (*)[3][3]
a         = 0x2000  // int (*)[3]  指向首行
&a[0]    = 0x2000  // int (*)[3]  指向首行
a[0]      = 0x2000  // int *       指向首元素
&a[0][0] = 0x2000  // int *       指向首元素

&a + 1      = 0x2024  // +36 字節(整個數組)
a + 1       = 0x200C  // +12 字節(一行 3*4)
&a[0] + 1  = 0x200C  // +12 字節(一行)
a[0] + 1    = 0x2004  // +4 字節(一個元素)
&a[0][0]+1 = 0x2004  // +4 字節

圖解記憶模型

二維數組 a[3][3] 內存佈局(行優先)
地址遞增 →
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│a[0][0]│a[0][1]│a[0][2]│a[1][0]│a[1][1]│a[1][2]│a[2][0]│a[2][1]│a[2][2]│
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
↑                       ↑                       ↑
a[0]                   a[1]                   a[2]     ← int * 步長 4
a / &a[0]                                    ← int (*)[3] 步長 12
&a                                                         ← int (*)[3][3] 步長 36

常見陷阱與最佳實踐

  1. 函數參數退化:`void foo(int a[][3])` 參數實為 `int (*)[3]`,必須指定列數;一維數組 `int a[]` 退化為 `int *`,失去長度信息。
  2. 動態分配二維數組:優先用一維連續內存 `int *p = malloc(m*n*sizeof(int))`,訪問 `p[i*n+j]`,避免指針數組 `int **` 的多次間接訪問與碎片化。
  3. 指針算術單位永遠是「所指類型大小」:`p + 1` 移動 `sizeof(*p)` 字節,這是理解所有偏移的鑰匙。

總結

搞清 「類型決定步長」,一維二維乃至多維數組的地址偏移就不再是謎。調試時多打印 `%p` 配合 `sizeof` 驗證,比死記硬背可靠得多。

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