6.2 參數(shù)傳遞 | Parameter passing

參數(shù)傳遞

形參初始化的機理與變量初始化相同。形參的類型決定了形參和實參的交互方式舶替。

  • 引用傳遞 passed by reference,函數(shù)被 傳引用調(diào)用 called by reference 璃饱。形參是引用,綁定到對應(yīng)實參上网持。引用形參也是其綁定對象的別名,即引用形參是對應(yīng)實參的別名长踊。
  • 值傳遞 passed by value 功舀,函數(shù)被傳值調(diào)用 called by value ,將實參的值拷貝賦給形參身弊。

傳值參數(shù)

初始化非引用類型的變量辟汰,傳值會拷貝初值,因此對變量的改動不會影響初始值阱佛。(對比于python)

指針形參

當(dāng)執(zhí)行指針拷貝操作帖汞,拷貝的是指針值,即地址值凑术◆嬲海拷貝后兩個指針是不同的指針。通過指針可以修改它所指對象的值麦萤,

指針形參的行為類似指針行為鹿鳖,可以改變實參的值扁眯,例如下:

void reset(int* ip){
    *ip = 0;  // ip所指對象置 0
    ip = nullptr壮莹;  // 改變ip本身的局部拷貝,不改變實參
}

int main(){
    int i = 42;
    reset(&i);         //由于是指針形參姻檀,需要取地址傳參命满。
    cout<<i<<endl;     //i=0
}

建議使用引用類型的形參(C++風(fēng)格)替代指針類型。

傳引用參數(shù)

對引用的操作實際上是作用在引用所引的對象上绣版。引用形參類似胶台。通過引用形參可以改變一個或多個實參的值。

void reset(int& i){
    i = 0;
}

int main(){
    int i = 42;
    reset(i);         
    cout<<i<<endl;     //i=0
}

使用引用避免拷貝

對較大類型對象和容器對象以及不支持拷貝的對象杂抽,為了性能或者可行性诈唬,只能通過引用形參訪問該類型的對象。

如比較兩個string對象的長度缩麸。由于string對象可能非常長不便于拷貝铸磅,而又不需要在函數(shù)中修改時,可以利用對常量的引用定義形參:

bool isShorter(const string& s1, const string& s2){
    return s1.size()<s2.size();
}

使用引用形參返回額外信息

C++函數(shù)只能有一個返回值杭朱。若要返回多個且有可能不同類型的值阅仔,可以構(gòu)造一個含有這些值類型的新類,或者直接傳入一個引用類型的形參并隱式返回該值弧械。

例如該程序同時統(tǒng)計在字符串中某個字符的首次出現(xiàn)位置索引和總次數(shù)八酒,可以編寫如下:

string::size_type find_char(const string& s, char c, 
                            string::size_type& occurs){
    auto ret = s.size();
    occurs = 0;
    for(decltype(ret)i=0; i!=s.size(); ++i){
        if (s[i]==c){
            if (ret == s.size()) ret = i;
        ++occurs;
        }
    }
    return ret;
}

int main(){
    string::size_type occ;
    string s = "bcdefghahaha";
    string::size_type r;
    r = find_char(s, 'a', occ);
    cout<<"First sub: "<<r<<";\nTotal occurs: "<<occ;
    return 0;
}

輸出:

First sub: 7;
Total occurs: 3

const 形參和實參

僅在用實參初始化形參時形參具有的頂層const會被忽略。因此可以傳給其常量和非常量刃唐。而只能給底層const的形參傳遞常量羞迷。

因此界轩,雖然C++允許定義同名而擁有不同形參列表的函數(shù),但下述兩個定義會被認(rèn)為是同一個衔瓮,盡管函數(shù)內(nèi)的形參功能不同:

void a(const int i){}
void a(int a){}

指針或引用形參參與const

具體的底層耸棒、頂層及可更改對象和初始化規(guī)則一致。

盡量使用常量引用

將函數(shù)內(nèi)不會改變其值的形參定義為常量引用报辱,既可以同時接受const和非const類型的實參与殃,又可以避免不需要的問題。

  • 問題1:非底層const引用無法使用字面值初始化碍现。
    void a(string a, int b){}
    void b(const string a, const int b){}
    a("str", 1) //error
    b("str", 1) //correct
    
  • 問題2:不同函數(shù)嵌套時幅疼,若內(nèi)層有函數(shù)是普通引用而無法接受const類的實參,會出錯昼接。

數(shù)組形參

數(shù)組的兩個特殊性質(zhì)對定義和使用作用在數(shù)組的函數(shù)有影響:

  • 不允許拷貝數(shù)組(如不可以a=b等):無法以值傳遞的方式使用數(shù)組參數(shù)
  • 使用數(shù)組時可能會被轉(zhuǎn)化為指針:為函數(shù)傳遞數(shù)組時實際上是傳遞了指向該數(shù)組首元素的指針爽篷。

因此,下列三個表達(dá)式等價慢睡,形參類型都是const int*逐工。

void a(const int*);
void a(const int[]);     //本意是作用與數(shù)組,實際形參是一個指針漂辐。
void a(const int[10]);   //10僅僅是期望的元素泪喊,實際不一定。

存在的問題:由于無法拷貝且會轉(zhuǎn)為指針髓涯,當(dāng)確實需要數(shù)組作為實參時袒啼,開始和結(jié)束位置難以確定。

使用標(biāo)記指定數(shù)組長度

管理數(shù)組實參的第一種方法:要求數(shù)組本身包含一個結(jié)束標(biāo)記纬纪。典型示例是c風(fēng)格字符串(以'\0'結(jié)尾)的處理:

void print(const char* cp){
    if (cp)          //指向內(nèi)容不為空
        while (*cp)  //所指字符不是空字符
            cout<<*cp++; 
}

使用標(biāo)準(zhǔn)庫規(guī)范

管理數(shù)組實參的第二種方法:傳遞指向數(shù)組首元素和尾后元素的指針蚓再,注意需要在使用函數(shù)前使用std::begstd::end提前取得這兩個指針:

void print(const char* beg, const char* end){
    while (beg!=end)
        cout<<*beg++;
}

顯式傳遞表示數(shù)組大小的形參

管理數(shù)組實參的第三種方法:定義一個表示數(shù)組大小的形參。在舊版本的 C++ 和 C 中常用這種方法包各。注意該形參的類型是size_t摘仅。

數(shù)組形參和const

和引用形參一樣,盡量將指針形參其定義為const類型避免不必要的問題问畅。

數(shù)組引用形參

若將變量定義為數(shù)組的引用娃属,可以直接使用。但是注意引用構(gòu)成的數(shù)組(X)-int& arr[10]對數(shù)組的引用-int (&arr)[10]按声。

傳遞多維數(shù)組

一般第一個維度使用指針傳遞膳犹,而操作必不可少的第二個維度,只能傳入其含有的元素個數(shù):

void print(int (*matrix)[10], int rowSize){}
// 等價于
void print(int matrix[][10], int rowSize){}

int matrix[][10] 看似是個二維數(shù)組的聲明签则,實際上聲明了一個指向含有10個整型元素的數(shù)組的指針须床。與 int (*matrix)[10] 一致。

main:處理命令行選項

往main()函數(shù)中定義參數(shù)以設(shè)置運行選項渐裂,如將這些命令傳遞給prog文件中的程序:prog -d -o ofile data0

int main(int argc, char* argv[]){}

第二個形參argv是一個數(shù)組豺旬,數(shù)組內(nèi)每項都是char指針钠惩;第一個形參表示字符串?dāng)?shù)量。第二個形參是數(shù)組族阅,所以main函數(shù)也可以定義為:

int main(int argc, char** argv){}

其中 argv 指向 char*篓跛。其內(nèi)容(數(shù)組)或指向的內(nèi)容(指針):

argv[0] = "prog"; //程序名
argv[1] = "-d";   //開始參數(shù)
argv[2] = "-o";
argv[3] = "ofile";
argv[4] = "data0";
argv[5] = 0;

含有可變形參的函數(shù)

常常會無法提前預(yù)知向函數(shù)傳遞的實參數(shù)量。為了使函數(shù)處理未知數(shù)量實參坦刀,C++11提供兩種方法:

  • 所有實參類型相同:傳遞名為 initializer_list 的標(biāo)準(zhǔn)庫類型愧沟;
  • 實參類型不同:可變參數(shù)模板

initializer_list 形參

expression description
initializer_list<T> lst; 默認(rèn)初始化空列表
initializer_list<T> lst{a, b, c...}; 列表初始化,內(nèi)部元素都是const
lst2(lst) 賦值鲤遥,前后二者共享元素
lst2 = lst 拷貝沐寺,前后二者共享元素
lst.size() 列表中元素數(shù)量
lst.begin() 返回指向lst首元素的指針
lst.end() 返回指向lst尾后元素的指針
  • initializer_list對象中的元素永遠(yuǎn)是常量值,無法改變盖奈。

  • 使用begin和end成員可以完成類似vector的迭代器操作混坞。

  • 向該類型形參中傳遞一個值的序列,必須把序列放在一對花括號內(nèi):

    initializer_list<string> str = a?  {"A", "B"}:{"C", "D", "E"};
    
  • 含有該類型形參的函數(shù)也可以含有其他類型的形參

省略符形參

省略符形參是為了便于C++程序訪問某些特殊的C代碼設(shè)置的钢坦,這些代碼使用了名為varargs的C標(biāo)準(zhǔn)庫功能究孕。通常省略符形參不應(yīng)用于其他目的

只能出現(xiàn)在形參列表最后一個位置爹凹,但注意大多數(shù)類類型的對象無法正確拷貝給該形參厨诸。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市逛万,隨后出現(xiàn)的幾起案子泳猬,更是在濱河造成了極大的恐慌,老刑警劉巖宇植,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異埋心,居然都是意外死亡指郁,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門拷呆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來闲坎,“玉大人,你說我怎么就攤上這事茬斧⊙” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵项秉,是天一觀的道長绣溜。 經(jīng)常有香客問我,道長娄蔼,這世上最難降的妖魔是什么怖喻? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任底哗,我火速辦了婚禮,結(jié)果婚禮上锚沸,老公的妹妹穿的比我還像新娘跋选。我一直安慰自己,他們只是感情好哗蜈,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布前标。 她就那樣靜靜地躺著,像睡著了一般距潘。 火紅的嫁衣襯著肌膚如雪候生。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天绽昼,我揣著相機與錄音唯鸭,去河邊找鬼。 笑死硅确,一個胖子當(dāng)著我的面吹牛目溉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播菱农,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼缭付,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了循未?” 一聲冷哼從身側(cè)響起陷猫,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎的妖,沒想到半個月后绣檬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡嫂粟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年娇未,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片星虹。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡零抬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宽涌,到底是詐尸還是另有隱情平夜,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布卸亮,位于F島的核電站忽妒,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜锰扶,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一献酗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧坷牛,春花似錦罕偎、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蹂楣,卻和暖如春俏站,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背痊土。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工肄扎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人赁酝。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓犯祠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親酌呆。 傳聞我的和親對象是個殘疾皇子衡载,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容