C 系統學習之六 函式

2022-08-19 12:06:12 字數 4632 閱讀 7511

典型的函式定義包括:返回型別、函式名、由0個或多個形參組成的列表以及函式體。

形參初始化的機理和變數初始化一樣。

有兩種方式:引用傳遞和值傳遞

當形參是非引用型別時,形參初始化和變數初始化一樣,將實參的值拷貝給形參。

當執行指標拷貝操作時,拷貝的是指標的值,拷貝之後,兩個指標是不同的指標。但通過指標可以修改它所指的物件。

拷貝大的類型別物件或者容器物件比較低效,甚至有的類型別根本就不支援拷貝操作。當某種型別不支援拷貝操作時,函式只能通過引用形參訪問該型別的物件。

當用實參初始化const形參時會忽略頂層const。因此,當形參有頂層const時,傳給它常量物件或者非常量物件都是可以的。

void fun1(const int i)

void fun2(int i)

上述兩個函式不能算是過載,兩個函式是一樣的,程式會報錯,fun2重複定義了fun1.

可以使用非常量初始化乙個底層const物件,但是反過來不行。同時乙個普通的引用必須用同型別的物件初始化。

陣列有兩個重要的特性:

儘管不能以值傳遞的方式傳遞陣列,但是可以將形參寫成類似陣列的形式

void print(const int*);

void print(const int);

void print(const int[10]);

以上三種形式的宣告等價

note:當函式不需要對陣列元素執行寫操作的時候,陣列形參應該是指向const的指標。只有當函式確實要改變元素值的時候,才把形參定義成指向非常量的指標。

當陣列作為函式形參時,因此應該提供一些額外資訊來確定陣列的確切尺寸,管理陣列形參有三種常用的技術:

要求陣列本身包含乙個結束標記。例如c風格字串以空字元結尾。

傳遞指向陣列首元素和尾元素的指標。

void print(const int *beg,const int *end)

;print(j, end(j)-begin(j));

形參可以是陣列的引用,此時,引用形參繫結到對應的實參上,也就是繫結到陣列上。

void print(int (&arr)[10])

cout << endl;

}

error_msg();

error_msg();  //注意值的傳遞要放在花括號裡

省略符形參

省略符形參是為了便於c++程式訪問某些特殊的c**而設定的。通常,省略符形參不應用於其他目的。省略符形參只能出現在形參列表的最後乙個位置。

返回型別是void型別的函式

返回乙個值的方式和初始化乙個變數或形參的方式完全一樣:返回的值用於初始化呼叫點的乙個臨時量,該臨時量就是函式呼叫的結果。

auto sz=getstring().size();    //getstring返回的string物件再呼叫size函式
呼叫乙個返回引用的函式得到左值,其他返回型別得到右值。

函式可以返回花括號包圍的值的列表。

vectorprocess()

;}

如果乙個函式呼叫了它自身,不管這種呼叫是直接還是間接的,都稱該函式為遞迴函式。

int factorial(int val)

求1x2x3x4......

因為陣列不能被拷貝,所以函式不能返回陣列。不過,函式可以返回陣列的指標或引用。

最直接的方法是使用型別別名

typedef int arrt[10];

using arrt=int[10];

int arr[10];    //arr是乙個含有10個整數的陣列

int *p1[10]; //p1是乙個含有10個整型指標的陣列

int (*p2)[10]=&arr; //p2是乙個指標,其指向乙個有10個整數的陣列

如果要定義乙個返回陣列指標的函式,則陣列的維度必須跟在函式名字之後,並且函式的形參列表應該先於陣列的維度。

int (*func(int a,int b))[10];
此函式返回的是乙個指向有10個整數陣列的指標。

任何函式的定義都能使用尾置返回,但是這種形式對於返回型別比較複雜的函式最有效,比如返回型別是陣列的指標或引用。

尾置返回型別跟在形參列表後面並以乙個->符號開頭。為了表示函式真正的返回型別跟在形參列表之後,我們在本應該出現返回型別的地方放置乙個auto。

auto func(int i)->int (*)[10];
如果同一作用域內的幾個函式名字相同但形參列表不同,稱為函式過載。注意必須是形參列表不同,僅僅只是返回型別不同不可以稱為過載。

頂層const不影響傳入函式的物件。乙個擁有頂層const的形參無法和另乙個沒有頂層const的形參區分開來。

int f1(int i);

int f1(const int i); //不構成過載,重複宣告了f1

int f2(int *i);

int f2(int *const i); //不構成過載,重複宣告了f2

但底層const不同,可以構成過載

int f1(int &i);

int f1(const int &i); //過載,新函式

int f2(int *i);

int f2(const int *i); //過載,新函式

note:最好只過載那些確實非常相似的操作。

const_cast在過載函式的情景中最有用。

const string &shorterstring(const string &s1, const string &s2)

string &shorterstring(string &s1, string &s2)

如果在內層作用域中宣告名字,它將隱藏外層作用域中宣告的同名實體。

void func()

int main()

預設實參、內聯函式和constexpr函式。

一旦某個形參被賦予了預設值,它後面的所有形參都必須有預設值。

string  screen(int i=10, int a=1, stirng s=" ");
在呼叫函式的時候省略該實參就可以。

在給定的作用域中乙個形參只能被賦予一次預設實參。

區域性變數不能作為預設實參。除此之外,只要表示式的型別能轉換成形參所需的型別,該表示式就能作為預設實參。

呼叫函式一般比求等價表示式的值要慢一些。

在函式的返回型別前面加上關鍵字inline。

一般來說,內聯機制用於優化規模較小、流程直接、頻繁呼叫的函式。

constexpr函式是指能用於常量表示式的函式。

定義constexpr函式要遵循:函式的返回型別及所有形參的型別都得是字面值型別,而且函式體中必須有且只有一條return語句。

constexpr int new_sz()

constexpr int foo=new_sz(); //foo是乙個常量表示式

為了能在編譯過程中隨時展開,constexpr函式被隱式地指定為內聯函式。

note:constexpr函式不一定返回常量表示式。

和其他函式不一樣,內聯函式和constexpr函式可以在程式中多次定義。不過,對於某個給定的內聯函式或者constexpr函式來說,它的多個定義必須完全一致。因此,內聯函式和constexpr函式通常定義在標頭檔案中。

兩項預處理功能:assert和ndebug

assert巨集常用於檢查「不能發生」的條件。

assert(expr);
如果expr為假,assert輸出資訊並終止程式執行,如果為真,assert什麼也不做。

assert的行為依賴於乙個名為ndebug的預處理變數的狀態。如果定義了ndebug,則assert什麼也不做,預設情況下沒有定義ndebug。

可以使用#define語句定義ndebug,從而關閉除錯狀態。

函式指標指向的是函式而非物件。和其他指標一樣,函式指標指向某種特定型別。函式的型別由它的返回型別和形參型別共同決定,與函式名無關。

int func(int a, string s);
該函式的型別是int(int , string).要想宣告乙個可以指向該函式的指標,只需要用指標替換函式名即可。

int (*p)(int ,string )  //未初始化
note:*p的括號必須加上

當把函式名作為乙個值使用時,該函式自動地轉換成指標。

int (*p)(int ,string )=func;
可以使用函式指標直接呼叫該函式,而不需要解引用該指標。

指向不同函式型別的指標之間不存在相互轉換,可以給函式指標賦值nullptr和0,表示指標沒指向任何乙個函式。

如果定義了指向過載函式的指標,編譯器通過指標型別決定選用哪個函式,指標型別必須與過載函式中的某乙個精確匹配。

和陣列類似,雖然不能定義函式型別的形參,但是形參可以是指向函式的指標。可以直接把函式作為實參使用,此時它會自動轉換成指標。

注意將decltype用於函式名時,返回的是函式型別,而非指標型別,如果要表示函式指標,需要自己加上*。

C 系統學習之四 陣列

與vector的異同 陣列中元素的個數也屬於陣列型別的一部分,編譯的時候維度應該是已知的,也就是說,維度必須是乙個常量表示式。預設情況下,陣列的元素被預設初始化。note 可以對陣列元素進行列表初始化,此時允許忽略陣列的維度。當指定了維度,則維度應比列表初始值的數量多,當維度比初始化列表的數量大時,...

C 系統學習 陣列

與vector的異同相同 都是存放型別相同物件的容器不同 陣列的大小確定不變,不能隨意向陣列中增加元素 1 定義和初始化內建陣列 陣列中元素的個數也屬於陣列型別的一部分,編譯的時候維度應該是已知的,也就是說,維度必須是乙個常量表示式。預設情況下,陣列的元素被預設初始化。note 定義陣列的時候必須制...

linux系統學習之管道

首先理解管道其實是乙個二進位制位元組流,它是核心為維持兩個或多個程序互相通訊的一種手段 一種ipc 如下圖所示 include include include include include define buf siz 10 int main int argc,char argv write 1,...