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

筆試題揭秘:為什麼計算數組元素個數必須用宏而非函數?

     編輯:關於C語言

經典面試題

某軟件公司筆試題:「請寫一個宏,計算靜態數組的元素個數」。標準答案:

#define countof(arr) sizeof(arr)/sizeof(arr[0])

核心追問:為什麼不能用函數?

若改用函數:

int countof(void *arr) {
    return sizeof(arr)/sizeof(arr[0]); // 錯誤!
}

答案:無法實現預期功能。

深度解析:sizeof 的編譯時計算特性

關鍵點 1:sizeof 在編譯期求值

sizeof 是操作符而非函數,其值在編譯階段確定。對於靜態數組,編譯器知道完整類型資訊,能計算整個數組大小;但傳遞給函數時,數組退化為指針,類型資訊丟失。

關鍵點 2:數組退化為指針

函數參數 void *arr 接收的是數組首元素地址(指針)。在 32 位系統上,sizeof(void*) == 4,與元素類型無關。

實測驗證代碼與結果

#include <iostream>

int getNum(void *pArr) {
    return sizeof(pArr); // 僅返回指針大小
}

int _tmain(int argc, _TCHAR* argv[]) {
    int myArr[10];
    int *pTest = new int(10); // 動態分配單個 int,非數組
    int myParam[10];
    char myChar[10];

    std::cout << "sizeof(int): " << sizeof(int) << std::endl;       // 4
    std::cout << "myArr: " << sizeof(myArr) << std::endl;           // 40 (10*4)
    std::cout << "pTest: " << sizeof(pTest) << std::endl;           // 4 (指針)
    std::cout << "getNum(myParam): " << getNum(myParam) << std::endl; // 4
    std::cout << "getNum(myChar): " << getNum(myChar) << std::endl;   // 4
    return 0;
}

輸出結果

sizeof(int): 4
myArr: 40
pTest: 4
getNum(myParam): 4
getNum(myChar): 4

MSDN 官方文檔佐證

sizeof 關鍵字 返回與變量或類型關聯的存儲字節數……
當應用於靜態維度數組時,sizeof 返回整個數組的大小。
sizeof 操作符不能返回動態分配的數組或外部數組的大小。

總結與最佳實踐

  • 宏方案:#define countof(arr) (sizeof(arr)/sizeof((arr)[0])) —— 在調用點保留完整類型資訊,編譯期計算,零開銷。
  • C++17 現代寫法:template <typename T, size_t N> constexpr size_t countof(T(&)[N]) { return N; } —— 類型安全、編譯期計算、拒絕指針退化。
  • 動態數組/指針:無法通過 sizeof 獲取長度,必須額外傳遞長度參數或使用容器(std::vector/std::span)。

這道題考察的不僅是 sizeof 語法,更是對 C/C++ 類型系統、編譯期與運行期邊界、參數傳遞機制 的深度理解。

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