在書寫C++代碼時,每每爲了令代碼更加簡潔高效、提升代碼可讀性,會對定義的函數有一些特殊的要求:好比不傳遞沒必要要的參數,以此來讓函數的參數列表儘量簡短。數組
當一個函數須要訪問一個數組元素時,出於上述緣由,每每也但願令傳入的參數儘量的少(至少我是這樣...)。函數
首先,引出一個例子,對於std::vector<typename>來講,每每只須要傳遞一個參數就足夠了(當只涉及單獨訪問該vector時的確如此),好比要編寫一個show函數,這個函數的功能是打印傳入容器的全部元素,並用空格將這些元素分隔開來。那麼當傳入容器爲vector時,這個show函數就會簡單無比:spa
1 void show(const std::vector<int> &ivec) { 2 for (size_t i = 0; i < ivec.size(); ++i) 3 std::cout << ivec[i] << " "; 4 std::cout << std::endl; 5 }
能夠看到,因爲標準庫中的vector包含size成員,使得咱們很容易獲取這個vector對象的大小,進而方便對這個vector進行訪問。此時,這個函數只須要一個參數就能夠完成容器的訪問工做(固然,對於這種容器,也能夠用迭代器進行訪問,此方式下函數的參數個數不變)。指針
那麼... 內置數組呢?code
很遺憾,答案是:不行。對象
在《C++ Primer 5th》中,做者指出:「由於數組是以指針的形式傳遞給函數的,因此一開始函數並不知道數組的確切尺寸,調用者應該爲此提供一些額外的信息。」(中文版第193頁,英文版第216頁) blog
書中繼而闡述了三種函數訪問數組的方式(原文爲:「管理指針形參的三種技術」):字符串
1. 使用標記指定數組長度博客
通俗地說,就是在傳入的這個數組中,含有一些標記數組結束的元素,好比C風格字符串(const char *),顯式地以'\0'字符做爲結尾標識符。那麼當遍歷到一個'\0'時,便可認定這個字符串結束,此時斷定訪問結束。但顯而易見,這樣的訪問方式不具備普適性,畢竟不少容器並不會包含一個指定的結尾標識,甚至一些容器都不能保證存入元素的順序固定。it
這裏,固然也能夠預約數組就是指定大小的(例如在源文件中聲明const LEN = 20; 或者預處理 #define LEN 20),儘管這樣和上述方法同樣,可使得函數只須要一個形參:
#define LEN 20 // const int LEN = 20; void show(const char *cp) { if (cp) while (*cp) std::cout << *cp++; } void show(const int lst[]) { for (size_t i = 0; i < LEN; ++i) std::cout << lst[i] << " "; std::cout << std::endl; }
可是,這樣的程序是不具備廣泛性的,咱們能夠很確定地說,咱們的數組必定不會正好包含20或更少的元素。
2. 使用標準庫規範
在標準庫中,對數組定義了begin和end方法,和迭代器不一樣的是,函數返回的是指針類型;和迭代器相同的是,用法基本一致...
void show(const int *beg, const int *end) { for (auto iter = beg; iter != end; ++iter) std::cout << *iter << std::endl; std::cout << std::endl; } /* 很遺憾,玩兒不轉 void show(const int lst[]) { for (auto beg = std::begin(lst); beg != std::end(lst); ++beg) std::cout << *beg << " "; std::cout << std::endl; } */
能夠看到,這時的show函數,至少須要兩個參數。固然,說到begin和end函數,不少人都會想到上面第二個這種方式,然而很遺憾,這種方式不行!此時,只能經過顯式地調用
show(std::begin(lst), std::end(lst));
來實現第一個函數的調用。但... 這並未達到「調用函數只包含一個參數」的指望。
至於這裏的第二種方式不行的緣由,我認爲是:在C++調用函數時,數組被自動轉換爲數組元素類型的指針類型(好比int lst[]就被轉換成了int *lst),這個過程是如此天然,就像是內置類型默認類型轉換通常(好比sum = 1 + 2.0,這裏的1就天然從int類型被轉換成了double類型)。所以,函數對這樣一個int *類型,天然無從對之繼續調用begin和end函數以獲得其首尾位置(這裏重點是沒法獲得尾位置)。故... 玩兒不轉。
3. 顯式傳遞一個表示數組大小的形參
這多是每一個學過C/C++的人最經常使用的方法了。經過顯式控制訪問元素的個數,保證指針前進的深度:
void show(const int lst[], size_t length) { for (size_t i = 0; i < length; ++i) std::cout << lst[i] << " "; std::cout << std::endl; }
形式很簡單,無須解釋。這裏須要注意的就是形參處的length的類型是size_t的,所以調用者傳入一個負值,頗有可能就美滋滋了。固然,也能夠修改成其餘類型,但這個問題不容忽視(見以前博客)。
我想說的是,這種方式下,依然沒達到「調用函數只包含一個參數」的指望...
可能只有強迫症纔會有這樣的糾結吧,但很欣慰的是,經過這個糾結,將調用函數訪問數組的三種方式系統地進行了說明闡述(方式2的第二種形式真的讓我很可惜...)。
固然,若是讀者有更好的方式(若是能只傳入一個參數便可訪問任意類型任意大小的數組,看在我糾結這麼久的份兒上,千萬要告訴我...),歡迎評論區分享,如有寫的不足的地方,敬請評論區斧正,在此感謝。