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。