[英]Passing an array as a function parameter in C++
在C ++中,數組不能簡單地作為參數傳遞。 這意味着如果我創建一個這樣的函數:
void doSomething(char charArray[])
{
// if I want the array size
int size = sizeof(charArray);
// NO GOOD, will always get 4 (as in 4 bytes in the pointer)
}
我無法知道數組有多大,因為我只有一個指向數組的指針。
在不更改方法簽名的情況下,我可以通過哪種方式獲取數組的大小並迭代它的數據?
編輯:只是關於解決方案的補充。 如果char數組,特別是初始化如下:
char charArray[] = "i am a string";
然后\\0
已經附加到數組的末尾。 在這種情況下,答案(標記為已接受)可以開箱即用。
使用模板。 這在技術上不符合您的標准,因為它會更改簽名,但不需要修改調用代碼。
void doSomething(char charArray[], size_t size)
{
// do stuff here
}
template<size_t N>
inline void doSomething(char (&charArray)[N])
{
doSomething(charArray, N);
}
Microsoft的Secure CRT函數和STLSoft的array_proxy類模板使用此技術。
沒有改變簽名? 附加一個哨兵元素。 具體來說,對於char數組,它可以是用於標准C字符串的空終止'\\0'
。
void doSomething(char charArray[])
{
char* p = charArray;
for (; *p != '\0'; ++p)
{
// if '\0' happens to be valid data for your app,
// then you can (maybe) use some other value as
// sentinel
}
int arraySize = p - charArray;
// now we know the array size, so we can do some thing
}
當然,那么你的數組本身不能包含sentinel元素作為內容。 對於其他類型(即非char)數組,它可以是任何非合法數據的值。 如果不存在此值,則此方法不起作用。
而且,這需要在呼叫者方面進行合作。 你必須確保調用者保留一個arraySize + 1
元素數組,並始終設置sentinel元素。
但是,如果您真的無法更改簽名,則您的選項相當有限。
它實際上曾經是一個非常常見的解決方案,用於傳遞數組第一個元素的長度。 這種結構通常稱為BSTR
(用於“BASIC字符串”),即使這也表示不同(但相似)的類型。
與已接受的解決方案相比,優點是使用標記確定長度對於大字符串來說是慢的。 顯而易見的是,這是一個相當低級別的黑客攻擊,既不考慮類型也不考慮結構。
在下面給出的形式中,它也僅適用於長度<= 255的字符串。但是,通過將長度存儲在多個字節中,可以很容易地擴展它。
void doSomething(char* charArray)
{
// Cast unnecessary but I prefer explicit type conversions.
std::size_t length = static_cast<std::size_t>(static_cast<unsigned char>(charArray[0]));
// … do something.
}
通常,在使用C或低級C ++時,您可能會考慮重新訓練大腦,從不考慮將數組參數寫入函數,因為C編譯器總是將它們視為指針。 從本質上講,通過鍵入這些方括號,你自欺欺人地認為正在傳遞一個真正的數組,完成大小信息。 實際上,在C中你只能傳遞指針。 功能
void foo(char a[])
{
// Do something...
}
從C編譯器的角度來看,它完全等同於:
void foo(char * a)
{
// Do something
}
顯然,nekkid char指針不包含長度信息。
如果您陷入困境且無法更改功能簽名,請考慮使用上面建議的長度前綴。 一個不可移植但兼容的hack是在數組之前的size_t字段中指定數組長度,如下所示:
void foo(char * a)
{
int cplusplus_len = reinterpret_cast<std::size_t *>(a)[-1];
int c_len = ((size_t *)a)[-1];
}
顯然,調用者需要在將數組傳遞給foo之前以適當的方式創建數組。
毋庸置疑,這是一個可怕的黑客,但這個技巧可以在緊要關頭擺脫困境。
如果它是無效的,strlen()將起作用。
您無法單獨使用charArray
確定大小。 該信息不會自動傳遞給該函數。
當然,如果它是一個以null結尾的字符串,你可以使用strlen()
,但你可能已經考慮過了!
考慮傳遞一個std::vector<char>
&參數,或一對指針,或指針加上一個size參數。
這實際上比C ++更多C,在C ++中你可能更喜歡使用std :: vector。 但是,在C中,無法知道數組的大小。 如果數組是在當前作用域中聲明的,編譯將允許你執行sizeof,並且只有在使用大小顯式聲明它時( EDIT:和“with a size”,我的意思是它是用整數大小聲明的)或者在聲明時初始化,而不是作為參數傳遞,感謝downvote)。
C中的常見解決方案是傳遞描述數組中元素數量的第二個參數。
編輯:
對不起,錯過了關於不想更改方法簽名的部分。 然后除了其他人所描述的之外沒有解決方案,如果在數組中有一些不允許的數據,它可以用作終結符(C字符串中的0,-1也很常見,但它取決於你的實際的數據類型,假設char數組是假設的)
為了使函數知道已傳遞給它的數組中的項數,您必須執行以下兩項操作之一:
您可以通過以下幾種方式完成后者:
嘗試使用strlen(charArray); 使用cstring頭文件。 這將產生包括空格的字符數,直到它到達結束時“。
您有責任在32位PC中接收4,這是正確的答案。 因為這里和這里解釋的原因。 簡短的回答是,你實際上測試的是指針而不是數組的大小,因為“數組被隱式轉換或衰減成指針。指針,唉,不存儲數組的維度;它不是甚至告訴你,有問題的變量是一個數組。“
現在您正在使用C ++, boost :: array是比原始數組更好的選擇。 因為它是一個對象,你現在不會丟失維度信息。
我想你可以這樣做:
size_t size = sizeof(array)/sizeof(array[0]);
PS:我認為這個話題的標題也不正確。
你可以用一個全局變量來存儲整個程序可以訪問的數組大小。 至少你可以將數組的大小從main()函數傳遞給全局變量,你甚至不必更改方法簽名,因為大小可以全局使用。
請看例子:
#include<...>
using namespace std;
int size; //global variable
//your code
void doSomething(char charArray[])
{
//size available
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.