在網路上無意間看到(原創) 如何使用function template傳遞array? (C/C++) (template)的幾篇文章後,我翻開我那塵封已久的C++ Primer 4/e,將有關陣列當做參數傳遞到函數的實作方法,整個初階到較為高階的做法,整理過後如下:
一般來說,我們若要讓函數傳遞陣列時,會寫以下:
/*
* @Function: void fnPrintArray(int arr[10])
* @Brief: Print the array content.
* @Input: int arr[10]
* @Output: array content.
*/
void fnPrintArray(int arr[10])
{
for(size_t i=0;i<10;++i)
{
std::cout << i << " " << std::endl;
}
}
但是此函式主要有兩個問題:
1. 若傳入的陣列只有包含3個元素時,會有out of range的問題。
2. 若傳入的陣列長度超過10,則無法完整印出該陣列內容。
針對上述問題的解法,C++ 在訂出reference這個概念後,array也可以用以下來代替:
/*
* @Function: void fnPrintArray(int arr[10])
* @Brief: Print the array content , and the input is by reference.
* @Input: int arr[10]
* @Output: array content.
*/
void fnPrintArray(int (&arr)[10])
{
for(size_t i=0;i<10;++i)
{
std::cout << i << " " << std::endl;
}
}
此一reference的技巧,在於限定傳入的陣列大小只有10,降低了使用上的風險。
其中,傳入的參數int (&arr)[10] 表示傳入一個reference,其reference到具有10個int元素的陣列。
若不加入括號的話:int &arr[10]表示傳入一個長度為10的陣列,每一個元素型態皆為int &。
不過,如此作法卻大大降低了可用性。
因此,如何管理好陣列大小,便成為一個令人頭痛的問題!根據C/C++ Primer 4/e 提出常用的解法有三:
1. 函式另外傳入兩個指標,分別指向陣列開頭以及陣列結尾。
2. 如1.所述,不同的是,將原本指到陣列結尾的指標轉而指向陣列結尾的下一個。
3. 函式須指明給定陣列的明確長度。
但是,此方法在實用性上略顯不足,難道沒有一個更有效的方法嗎?
我們可以利用C++的template來幫我們實現這個方案。
#include <iostream>
using namespace std;
/*
* @Function:
template<typename T,size_t N>
void fnChange(T (&arr)[N])
* @Brief: Let each element of array increase by one.
* @Input: 1D array
* @Output: The array whose elements all increase by 1
*/
template<typename T,size_t N>
void fnChange(T (&arr)[N])
{
for(size_t i=0;i<N;++i)
arr[i]+=1;
}
int main(int argc, char * argv[])
{
int arr1D[3]={1,2,3}; // Create 1D array.
int arr2D[3][2] = { {1,2},{3,4},{5,6}}; // Create 2D array.
// Show the initialized result.
for(int i=0;i<3;++i)
{
cout << arr1D[i] << endl;
}
fnChange(arr1D);
// Show the result.
for(int i=0;i<3;++i)
{
cout << arr1D[i] << endl;
}
return 0;
}
上述程式碼,利用樣板特化的技巧,讓函式不用帶入陣列大小,便可透過樣板參數幫我們自動得知陣列大小,以利函式功能的撰寫。
因此,舉一反三,我們可以藉此程式碼推廣至二維陣列,範例程式碼如下:
#include <iostream>
using namespace std;
/*
* @Function:
template<typename T,size_t M,size_t N>
void fnPrint2DArray(T (&arr)[M][N])
* @Brief: Print the content of 2D Array.
* @Input: 2D array.
* @Output: None.
*/
template<typename T,size_t M,size_t N>
void fnPrint2DArray(T (&arr)[M][N])
{
for(size_t i=0;i<M;++i)
{
for(size_t j=0; j<N; ++j)
{
cout << arr[i][j] << " ";
}
cout << endl;
}
}
int main(int argc, char * argv[])
{
int arr2D[3][2] = { {1,2},{3,4},{5,6}}; // Create 2D array.
// Print 2D array.
fnPrint2DArray(arr2D);
return 0;
}
因此,對於陣列的參數傳遞,我們可以利用樣板的功能來幫我順利達成。似乎一切在這邊有了完整的解答。:)
Reference
C++ Primer 中文版 4/e page. 110 , 240~241, 632~633.
(原創) array傳進function該怎麼寫才好? (C/C++) (C) 推薦閱讀!
近期迴響