c primer 學習(四) 函式

2021-07-16 01:54:16 字數 4599 閱讀 4348

之所以跳過了原書第五章的「語句」,是因為這個東西實在沒啥意思,只要學過一點c,或者任何程式語言的應該都會,要說知識只有一點,就是後邊的異常處理,不過這個在後邊章節也要詳細講,只要記住乙個try}catch(error){}就可以了。

但是第五章的題都是不錯的,建議大家乙個個做一下,其實感覺c++primer的乙個優點就是題目不錯,也不給你整些八皇后啥的,都是和語言、語法細節相關的題,很有意義,畢竟你給我出些帶點演算法的不如我直接去刷演算法導論呢。

開始第6章吧。

形參和實參使用的注意:型別匹配,數量匹配。實參的型別要可以轉化為形參的才可以,比如intf(int),好歹得給個double的數,可以轉化為int。

函式最外層作用域的區域性變數不能和函式形參名一樣,因為形參會隱藏外部變數。

函式的返回型別不能是陣列,或函式型別,但可以是指向陣列和函式的指標。

函式塊執行期間的物件成為自動物件,形參是自動物件,開始時申請空間,結束時銷毀。就是個名詞,沒什麼意義。

區域性靜態物件:讓區域性變數生命週期一直持續,知道程式結束。區域性靜態變數初始化為0。

函式宣告:不需要形參名字,只要型別,因為不包含函式塊,名字沒卵用。

至於分離式編譯,簡單說就是檔案分開寫,函式宣告寫在標頭檔案裡,函式寫在別的檔案裡,main再寫乙個,這樣比較清晰,而且測試的時候比較方便(我的經驗)。

引數傳遞

乙個有趣的例子:void swap(int *a,int *b)

int t=*a;

*a=*b;

*b=t;

想說的不是這個例子,而是給他傳遞的時侯。如果前邊宣告為int p=0,q=1;那麼呼叫時就要寫為swap(&p,&q);因為我們需要p和q的位址,作為值傳遞出去。可是如果宣告為:int i=0,j=1,*p=&i,*q=&j;時,只需寫為swap(p,q);因為p和q的值就已經是位址了。

引用傳遞:此時形參就是實參的引用,別名,改變形參當然就是改變實參了。引用可以返回額外資訊,這時外部也可以使用此引用。如書中例子:

string::size_type find_char(const string&s,char c,string::size_type &occurs)

if(...)

return x;}此時occurs被隱式返回了。

const成為形參或實參時:注意頂層const。再次複習一下什麼事頂層const?乙個重要特徵就是拷貝時會忽略掉頂層const,如:const int c=4;int i=c;所以當使用實參初始化形參時也會忽略掉形參的頂層const,即:形參有頂層const,可以傳遞常量/非常量。在函式過載中,可以同名,但是形參要不同,所以擁有頂層const形參和沒有的函式都一樣,不可以過載。至於底層const,可以用非常量初始化,但反之不可以。

而指標與引用的const,規則類似初始化物件。簡單地說, 就是:const指標可以指向非常量(但不可用於更改,並且反之不行);const引用可以引用非常量(不可更改,反之不行);const引用可使用字面值(普通引用不行)。所以在函式中可以把實參看做右邊值,所以有以下規定(假設函式的形參是變數指標或變數引用):

實參不能是const的位址;實參不能是const的引用。

陣列形參

複習一下陣列的性質:1.不允許拷貝。2.陣列名會轉換為指標。所以陣列作為形參時,有以下呼叫形式:

void print(const int*)==void print (const int)==void print (const int[10]),他們都是對陣列名--指標的呼叫,所以即使規定大小後編譯器無法檢驗大小。注意不超過陣列的大小很重要,可以使用標準庫規範限制(begin(),end()),也可以使用陣列的引用直接限制大小,如:void print(int (&array)[10]),這樣就必須傳入大小為10的陣列。注意括號(&array),表示是陣列的引用,不是引用的陣列。

多維陣列當做形參,除第一維之外都要有大小,因為他們是陣列型別的一部分,形式如下:void print(int (*array)[10])//二維

若處理可變形參,當實參型別一致時,可使用initializer_list型別。可使用操作如下:

initializer_listlst//預設初始化

initializer_listlst//固定初始化,元素型別是const

lst2=lst(或者lst2(lst))//lst和lst2共享元素,不會拷貝

lst.size()lst.begin()lst.end()//同容器成員函式

省略符形參

void foo(...)就是這個...用於特殊的c**,他們使用了varargs庫功能,而且省略號只能放在形參最後乙個位置。

返回一般在有return的迴圈語句後要有乙個return,為防止迴圈結束後無法返回。

返回的值是物件的臨時拷貝或副本。引用型別返回的是引用。不能返回區域性物件的引用或指標,因為結束函式後引用/指標無法指向原來有效的記憶體空間。

返回的物件若是指標,引用或類型別,可以使用其資料型別具有的成員函式,如:string shortstring();auto sz=shortstring().size();

呼叫乙個返回引用的函式,返回的是左值,否則返回的是右值,左值可以被賦值。如:char &get_val(string s,string::size_type x)可以使用:get_val(s,0)='a';這樣就將s[0]改為了a。當然你要保證可以更改!

返回值可以用花括號包含{},內定型別只能乙個,自定類型別則可自定包含幾個。

主函式的返回值,當返回0時代表正確,其他值不一定。cstdlib中有2個量,表示返回成功和失敗:exit_failure, exit_success。

遞迴:不好講,道理都懂,不過設計乙個好的遞迴函式還是很要經驗的。

返回陣列指標:陣列不能被拷貝,所以不能返回陣列,但可以是他的指標或引用,宣告如下:

1.int (*func(int i))[10];這樣就返回了有10個int型元素的陣列,且形參是int型。也可使用型別別名:typedef int arr[10];(或者:using arr=int [10];)//宣告如下:arr* func(int i);

2.複習一下typedef:將某個型別給他別名,*,&,等運算子算原來型別。如:typedef double *p;這時p是型別:double* 的別名。

3.也可使用尾置返回:就是將返回型別放在最後,對上述例子舉例如下:auto func(int i)->int(*)[10];

4.還可使用decltype:用於返回指向乙個已有陣列的指標。如下:int x=;decltype(x) *arr(int i)注意:對x取decltype得到的是大小為3的陣列,要返回指標必須加個「*」號。

過載其實過載挺簡單的,不知道為什麼書會講這麼多。

1.形參是頂層const不會影響拷貝,會導致過載失敗。如果形參是個引用或指標,則const是底層的,可過載。

2.使用const_cast,在過載中便於轉換const為非const,書上的例子非常經典,原函式:const string &fun(const string &s1,const string &s2),現在實現:實參是非const,返回也是非const:string &fun(string &s1,string &s2)

3.呼叫過載函式:

函式匹配:先形成候選函式。條件:1.同名。2.宣告在呼叫點可用。在函式內宣告同名函式會隱藏外部的同名函式。再選出可行函式:1.形參實參數量相同。2.形參實參型別相同,或實參可用轉換為形參的型別。然後精確匹配:盡量不轉換型別。多個引數匹配的優先順序為:每個實參的匹配不劣於其他函式;至少有乙個優於其他。若不滿足,則導致呼叫二義性,過載失敗。

實參的型別轉換:最佳匹配的優先順序:1.實、形型別一致;實參從陣列、函式型別轉換為指標型別;實參的頂層const增、減。2.const轉換。3.型別提公升。4.算數型別轉換或指標轉換。5.類型別轉換。

tip,所有算數轉換的優先順序一致。int到long,和int到double是一樣的優先順序。

函式指標

這一節我認為是比較難的,因為我覺得他舉的例子太少了,都是乾巴巴的概念和辨析,所以我推薦認真做這一小節的最後一道題,非常有意義。

函式指標指向的是函式。只需將一般函式的名字變為:name1→(*name2)即可。給函式指標賦值時形式如下:name2=name1;name2=&name1;取位址符可選,因為把函式名作為值時,名自動轉換為指標。而呼叫時也不需要解引用,如:int i1=name2(/**/);int i2=*name2(/**/)原理同上。

指向不同函式型別的指標不存在轉換。但可賦值nullptr。而過載時必須:形參匹配;返回值匹配。

形參不能是函式型別,但可以是指向函式的指標。同理我們可以使用別名簡化形參列表。如:typedef bool func(const string&),等價於typedef decltype(fun) func。假設:bool fun(const string&)。

返回不能是函式,但可以是函式的指標。類似上邊:using f=int(*)(int*,int*),此時乙個返回函式指標的函式:f f1(int)即可,因為f本身是乙個函式指標。若f如下:using f=int (int*,int*),則需要:f *f1(int),才是返回函式指標的函式。也可直接宣告:int (*f1(int))(int*,int*)或是尾置:auto f1(int)->int(*)(int*,int*)。同樣的也可使用auto和decltype,但需要知道返回的是某乙個確定函式。

至於incline和constexpr函式,比較簡單,就不說了。

C Primer 學習筆記(四)

2019年4月16日 3.9.1多維陣列 我們可以定義多維陣列。每一維用乙個方括號對來指定,例如 int ia 4 3 關於多維陣列的初始化。為了索引到乙個多維陣列中,每一維都需要乙個方括號對,不然意義就會發生變化。在c 中,多維陣列的索引訪問要求對程式設計師希望訪問的每個索引都有一對方括號。3.9...

C Primer學習第四天

第四章 陣列和指標 c 語言提供了兩種類似於vector和迭代器型別的低階復合型別 陣列和指標。與vector型別相似,陣列也可以儲存某種型別的一組物件 而它們的區別在於,陣列的長度是固定的。陣列一經建立,就不允許新增新的元素。指標則可以像迭代器一樣用於遍歷和檢查陣列中的元素。現代c 程式應盡量使用...

C Primer學習筆記(7)函式

1 函式呼叫做了兩件事情,用對應的實參初始化函式的形參,並將控制權轉交給被掉函式 主調函式的執行被掛起,被掉函式開始執行。2 函式體是乙個作用域。3 函式不能返回另乙個函式或者內建陣列型別,但是可以返回指向函式的指標或者指向陣列元素的指標。4 c 是一種靜態強型別語言,對於每一次的函式呼叫,編譯器都...