簡體   English   中英

在C ++中將數組作為函數參數傳遞

[英]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數組是假設的)

為了使函數知道已傳遞給它的數組中的項數,您必須執行以下兩項操作之一:

  1. 傳入尺寸參數
  2. 以某種方式將大小信息放入數組中。

您可以通過以下幾種方式完成后者:

  • 使用NULL或其他一些不會出現在普通數據中的標記來終止它。
  • 如果數組包含數字,則將項目計數存儲在第一個條目中
  • 如果數組包含指針,則存儲指向最后一個條目的指針

嘗試使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM