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

C語言入門教程(四):數組與指針的深度關係——sizeof陷阱與參數傳遞真相

     編輯:關於C語言

C語言入門教程(四):數組與指針的深度關係——sizeof陷阱與參數傳遞真相

數組與指針是 C 語言最易混淆又最核心的關係。本節通過 sizeof 實測、函數參數退化、內存佈局圖解,徹底釐清二者異同,建立正確直覺。

一、字符串本質:字符數組 + 結束符

內存佈局:"Shatner"
索引:    0  1  2  3  4  5  6  7
內容:    S  h  a  t  n  e  r  \0
地址:    100 101 102 103 104 105 106 107
```

C 不記錄數組長度,約定 \0 (ASCII 0) 為結束標記。sizeof 可獲取佔用字節數(含結束符)。

二、sizeof 陷阱實測

代碼:sizeof_demo.c

#include 

void SayHello(char msg[]) {
    printf("msg occupies: %zu\n", sizeof(msg));  // 輸出指針大小!
}

int main() {
    printf("Shatner occupies: %zu\n", sizeof("Shatner"));  // 8 (含\0)
    
    char msg[] = "Hello C";
    printf("msg occupies: %zu\n", sizeof(msg));  // 8 (含\0)
    
    SayHello(msg);  // 輸出 8 (64位) 或 4 (32位)
    
    char *msgp = msg;
    printf("msgp occupies: %zu\n", sizeof(msgp)); // 8/4 指針大小
    
    return 0;
}

輸出結果(64位系統)

Shatner occupies: 8
msg occupies: 8
msg occupies: 8      // 函數內:指針大小!
msgp occupies: 8

核心解析

表達式類型sizeof 結果原因
"Shatner"char[8]8字符串字面量是數組
msg (在 main)char[8]8數組聲明分配內存
msg (在 SayHello)char*8/4參數退化為指針
msgpchar*8/4指針變量

三、數組參數退化鐵律

void func(int arr[10])    // 等價於
void func(int arr[])      // 等價於
void func(int *arr)       // 完全一致!

編譯器處理:函數參數聲明為數組時,自動轉換為指針。數組大小信息丟失,sizeof 僅得指針大小。

四、數組 vs 指針:本質區別

五、&arr 與 &arr[0] 的類型差異

int arr[5];
int *p1 = &arr[0];     // int*  - 指向首元素
int (*p2)[5] = &arr;   // int(*)[5] - 指向整個數組

printf("%p %p\n", p1, p2);  // 值相同
printf("%p %p\n", p1+1, p2+1);  // 差異巨大!
// p1+1: +4 字節 (下一個 int)
// p2+1: +20 字節 (下一個 int[5])

六、實戰:在函數中獲取數組長度

錯誤嘗試:

void bad_len(int arr[]) {
    int n = sizeof(arr) / sizeof(arr[0]);  // 永遠是 1 (指針/元素)
}

正確方案:

  1. 額外傳遞長度:void good_len(int arr[], int n)
  2. 結構體封裝:
    typedef struct { int *data; int len; } IntArray;
  3. 哨兵值:字符串用 \0,整數數組可用特定值(如 -1)結尾
  4. 宏計算:#define ARR_LEN(arr) (sizeof(arr)/sizeof(arr[0])) **僅在數組聲明作用域有效**

七、指針算術與數組索引等價性

int arr[5] = {10,20,30,40,50};
int *p = arr;

arr[2]    // 30
*(arr+2)  // 30
p[2]      // 30
*(p+2)    // 30
// 完全等價!編譯器將 a[b] 統一翻譯為 *(a+b)

八、二維數組與指針

int matrix[3][4];
// 類型:int[3][4] - 3行4列
// 內存連續佈局:row0_col0, row0_col1... row2_col3

int (*p)[4] = matrix;  // 指向「4個int的數組」的指針
// p[0] → 第0行 (int[4])
// p[1] → 第1行
// p[i][j] 等價於 *(*(p+i)+j) 等價於 matrix[i][j]

九、本節作業

  1. 編寫函數 void print_arr(int *arr, int n) 打印數組
  2. 實驗:int a[5]; printf("%p %p\n", a, &a); printf("%p %p\n", a+1, &a+1); 觀察地址增量
  3. 閱讀 man 3 strlen 理解字符串長度計算(尋找 \0)
  4. 思考:為什麼 C 設計數組參數退化為指針?(提示:性能、兼容性)

總結

「數組在聲明處是數組,在表達式中(含參數傳遞)退化為指針」。牢記:sizeof 區分二者,&arr 獲取數組指針,函數傳遞需額外帶長度。這是 C 語言「手動管理」哲學的核心體現——**沒有免費的午餐,長度信息不自動傳遞**。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
特性數組指針
內存分配編譯期/棧上分配元素空間僅分配指針變量空間(8/4字節)
地址值&arr == &arr[0] (值相同)&p != p (指針變量自身地址 vs 指向地址)
可修改性不可修改地址 (非左值)可修改指向 p = &other;
sizeof整個數組字節數指針變量大小
類型int[5]int*