精華區beta C_and_CPP 關於我們 聯絡資訊
ptt.cc BBS 站 C_and_CPP 板 FAQ (0.2版) 陣列的問題 Q: 我傳一個陣列到函式,在函式中要怎麼知道裡面有幾個元素? void DoSomething(float* data) { /* 要怎麼知道data裡面有幾個元素呢? */ } A: C 語言無法真的傳整個陣列到函式中,只能傳指標。在函式中,是無法從 指標來決定其相應的陣列有幾個元素的。 註:除非是「指向整個陣列的指標」,這種情形根本也沒有必要在函 式定義中再寫程式去算有幾個元素,因為參數本身就很明確的指定了: void DoArrPtr(int (*arr_p)[3]) /* arr_p 是指向 int[3] 的指標 */ { /* ...... */ } 如果是字串陣列的指標,因為字串的的結束字元是 '\0',那麼就能用strlen() 函式來計算出 '\0' 之前的字元的個數。 其他型別的元素所成的陣列,除非也有一個 sentinel 值(意指該值能夠 與正常的元素值有所區分,而又屬於相同的型別,像字串陣列的 '\0' 就是),可以在呼叫端將該值放入陣列最後一個元素的下一個位置。傳入 函式後,就能逐一檢查每一元素,並累計其個數,直到遇到此 sentinel 值為止。 比較常見的做法是函式的宣告多一個整數參數(可用 int, 較嚴謹的做法 是用 size_t),由呼叫端負責決定陣列的個數(參考上一則FAQ),並傳給 這個整數參數。 至於 C++,除了上述的做法可以用之外,也可利用 reference type 配合 function template 來決定陣列的元素個數,但只限於編譯時期就能夠決 定元素個數的情形,呼叫端傳進去的必需是一個靜態宣告的陣列變數,不 能是動態陣列的指標。如: template <size_t SIZE> void foo(float (&arr)[SIZE]) // C++ 可以真的傳陣列 { std::cout << "The array has " << SIZE << " elements\n"; // ... } int main() { float myarr1[10]; // 靜態宣告的陣列 float myarr2[20]; // 同上 foo(myarr1); foo(myarr2); return 0; } by Khoguan Phuann ----------------------------------- 敬請指正錯誤,或提出更合適的答案。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 220.130.208.167 ------------------------------------------------------------------- 以下更精闢的解說由某位不願具名的網友所提供 template<class Array, size_t Size> size_t dimof(Array const (&)[Size]) { return Size; } 這個經典的 dimof 是用到 reference to Array 參數列中,省略 Array 的變量名稱是為了強調 template 可以直接推導出 Size。 對照 C 慣用的: #define dimof(Array) (sizeof(Array) / sizeof(Array[0])) 另外,如果沒有 reference(在 C 中),可以直接把元素個數填進去: void foo(int Array[5]); 但實際上「5」只是寫好看的,在 foo 中它自動退化成 pointer,例如: int a[4]; foo(a); // OK. 因為退化成 pointer 了,編譯器不會檢查出有問題 因此在 C 中比較推薦: void foo(int Array[], size_t N); 這樣的寫法。 實際上 C/C++ 是可以用 pointer to array 來「確實傳遞 Array」,例如: void foo(int (*Array)[5]) { *Array; // 它「真的」是一個 int [5] } int a[4]; foo(&a); // 這次編譯器就會抓出來了。 但這種寫法不自然,容易混淆,不如用前面常見的方法。 C++ (template)版的 dimof 優點是可以自動排除指標的誤用,也就是型別 安全(限制呼叫端一定要傳剛好大小的 Array 過來)。但 C 常用傳 Array 的方式比較有彈性(由呼叫端決定 Array 的大小)。因此可視情況決定用哪 一種,或乾脆傳一個 Container,例如 vector。