復習 C++ 函數(一)參數傳遞/return語句/返回類型


C++ 函數(一)參數傳遞/return語句/返回類型

6.1 基礎

函數的返回值不能是數組或函數類型,但可以是指向數組或函數的指針

6.1.1 作用域,局部對象

函數體是一個塊,構成一個新的作用域,其中定義的變量和形參都是局部變量

在函數體外部定義的對象存在於程序的整個執行過程中

自動對象:

只存在於塊執行期間的對象,例如形參,函數終止,形參會被銷毀,局部變量如果本身不帶初始值,則會執行默認初始化,意味內置類型的未初始化局部變量將產生未定義的值

局部靜態對象

定義為static類型,如果沒有顯式的初始值,則將初始化為0

函數聲明

又叫函數原型,不包含函數體,無需形參名(也可以有)

6.2 參數的傳遞

pass by value

將實參的值拷貝后賦值給形參,對形參的操作不會影響實參

指針形參

傳遞指針,拷貝的是指針的值,拷貝后的兩個指針是不同的指針,但是由於指針可以間接的訪問所指的對象,所以可以通過指針修改它所指的對象值

void reset(int *p){ 
	*p = 0;//改變了指向的對象的值
	 p = 0;//只改變了p的局部拷貝,實參未改變 
}

C++建議用引用類型的形參代替指針

pass by reference

void reset(int &p){}

改變引用形參,就是改變初始化形參的實參

盡量使用引用來避免拷貝,而且有些類不支持拷貝(比如IO類)

6.2.2 const形參,const實參

頂層const作用於對象本身,形參有頂層const時,傳遞常量或非常量對象都可以(實參初始化形參時會忽略頂層const)

void func(const int n){}
const int i = 1;
int j = 2;
func(i);
func(j);
//上面兩種調用方法都正確
//由於這種忽略,導致下面兩種函數其實是一樣的,所以不是重載
void func(const int i);
void func(int i);

6.2.3 指針,引用形參

可以使用非常量初始化一個底層const,但是不能反過來,一個普通的引用必須用同類型的對象初始化

int i = 0;
const int ci = i;
string::size_type ctr = 0;
reset(&i);//形參類型為int*
reset(ci);//錯誤,不能使用const int對象的指針去初始化int*
reset(i);//形參為int&時
reset(ci);//不能將普通引用綁定到const對象ci上
reset(42);//不能綁定字面值
reset(ctr);//類型不匹配,ctr是無符號類型

可以使用字面值初始化常量引用

盡量使用常量引用,避免限制函數能接收的實參類型(字面值)

6.2.4 數組形參

數組的兩個特殊性質:

  1. 不能拷貝數組:無法值傳遞
  2. 使用數組時通常轉化成指針:傳遞參數時,實際上傳遞的是指向數組首元素的指針

數組的大小對函數調用沒影響

管理指針形參:(主要是長度問題)

一種方法是使用標記指定長度,只適用於C語言中類似C風格字符串,以空字符結束

所以更實用的是另外兩種方法:

  1. 標准庫函數begin,end

    void print(const int *beg,const int *end){
    	while(beg!=end){
    		cout<<*beg++<<endl;
    	}
    }
    int j[2] = {0,1};
    print(begin(j),end(j));
    
  2. 顯式傳遞一個數組大小形參

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

數組引用形參/const形參

不需要改變數組元素值時,最好加上const

//數組的引用,維度是類型的一部分
void print(int (&arr)[10]){}
//必須加(),否則arr就是引用的數組,而不是具有10個整數的整型數組的引用
//傳遞參數時,只能將函數作用域大小為10的數組
int i[2] = {2,1};
print(i);//錯誤

多維數組

C++的多維數組就是數組的數組

數組的數組,首元素本身就是一個數組,第二維不能省略

void print(int (*matrix)[10],int rowsize);
//如果沒有(),則是十個指針構成的數組,而不是指向含有10個整數的數組的指針
void print(int matrix[][10],int rowsize);

6.2.5 main(int argc,char *argv[])

6.2.6 可變形參

處理不同數量的實參的函數:

  1. 如果所有實參的類型相同,可以傳遞標准庫類型:initializer_list

  2. 不同則寫可變參數模板

  3. 省略符(一般只用於與C函數交互的接口程序)

    形式:void fun(parm_list,...)

    void fun(...)

    僅用於C和C++通用的類型

initializer_list對象中的元素永遠是常量值

拷貝,賦值一個initializer_list對象不會拷貝列表中的元素,拷貝后原始列表和副本共享元素

list2(list1);//拷貝
list2 = list1;//賦值


void error_msg(initializer_list<string> il){
    //initializer_list有begin,end,所以可以使用指針,范圍for循環遍歷列表
}
//調用:expected,actuall為string對象
error_msg({"functionX",expected,actuall});

6.3 返回值 (return)

無返回值的return后可以什么都沒有,也可以跟另外一個返回void的函數

不要返回局部對象的引用或指針

函數結束后,局部變量的內存空間會被釋放

const string&manip(){//下面兩個都錯
	string ret;
	if(){
		return ret;//局部對象
	}
	else{
		return "empty";//臨時局部變量
	}
}

引用返回左值:

調用運算符優先級和點,箭頭相同

//符合左結合律,返回指針,引用,類的對象:
auto s = func(s1,s2).size();

調用返回引用的函數會得到左值,其他類型為右值

因此這種情況下函數的返回值可以像使用其他左值一樣:

char &get_val(string &str,string::size_type ix){
	return str[ix];
}
int main()
{
	string s("a value");
	get_val(s,0) = 'A';
	//s[0]被改為A
    return 0;
}
//返回值是個常量引用就不能賦值了

列表初始化返回值

vector<string>pro(){
	return {"one","two"};
}

如果返回內置類型則{}中最多包含一個值

返回數組指針

數組不能拷貝,所以函數不能返回數組

使用類型別名簡化返回數組的指針和引用

//下面兩行代碼是等價的
typedef int arr[10];
using arr = int[10];
//返回一個指向含有十個整數的數組的指針
arr* func(int i);
//如果不使用類型別名:
Type (*function(parameter_list))[dimension]
int (*func(parameter_list))[10];
//必須有*之外的(),否則聲明的函數返回類型就會是指針的數組,而不是數組的指針

尾置返回:

函數真正的返回類型在形參列表之后,格式:

auto func(int i)->int(*)[10];
//任何函數定義都能使用尾置返回

decltype

如果知道函數返回的指針指向哪個數組,則可以使用decltype

int o[] = {12,3};
int o2[] = {1,2};
decltype(o)* arrptr(int i){}

decltype的結果是數組,所以還要加上*


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM