【C++養成計劃】深入淺出——函數(Day6)

寫在前面:大家好!我是【AI 菌】,一枚愛彈吉他的程序員。我熱愛AI、熱愛分享、熱愛開源! 這博客是我對學習的一點總結與記錄。如果您也對 深度學習、機器視覺、算法、Python、C++ 感興趣,可以關注我的動態,我們一起學習,一起進步~
我的博客地址爲:【AI 菌】的博客

上一篇:【C++養成計劃】控制程序流程——判斷與循環(Day5)
昨天,我們學習了C++程序中的兩大控制流程:判斷和循環。今天,我們來學習編程語言中一個很重要的知識板塊:函數


1. 初識函數

一說到函數,對於編程小白,可能首先聯想到的是數學中的函數公式:y=f(x)y=f(x)。其實呢?C++函數與數學函數式子是有一些相通之處,比如,它們一般都有着輸入和輸出;函數式中的映射關係,對應到C++函數中就是一種邏輯關係。
不同的是,在C++中,函數是一組一起執行一個任務的語句。每個 C++ 程序都至少有一個函數,即主函數 main() ,並且程序從主函數處開始執行。具體可參見:【C++養成計劃】基本語法(Day2)

(1) 爲何需要函數

其實,對於小型的應用程序來說,完全可以使用main()實現所有功能。但是當程序越來越大,越來越複雜時,若想要main()中的代碼依然保持簡潔、邏輯清晰易讀,就必須使用函數了
函數能夠很好地劃分和組織程序的執行邏輯。通過使用函數,可以將原本複雜冗長的程序劃分爲依次調用的程序塊。

(2) 函數定義

在C++ 中,函數定義的一般形式如下:

return_type function_name(parameter list)
{
	函數主體
}

由此可知,函數主要有如下4個組成部分:

  1. 返回類型 return_type。是指函數返回值的數據類型,一個函數可以返回一個值。有些函數只執行某些操作不返回值,那麼返回類型要設置爲viod
  2. 函數名稱 function_name。就是函數的名字,由我們自己設定,在調用函數時用到。
  3. 參數列表 parameter list。參數就像是佔位符。當函數被調用時,你向參數傳遞一個值,這個值被稱爲實際參數。參數列表包括函數參數的類型、順序、數量。參數是可選的,也就是說,函數也可以不包含參數。
  4. 函數主體。是函數的主體結構,由執行一個任務的若干語句構成。

下面舉一個簡單的例子,用函數實現:計算圓形的面積

#include<iostream>
using namespace std;

const double Pi =3.14;
//定義Area_circle函數,實現對圓求面積
double Area_circle(double r)
{
	return Pi*r*r;  //返回圓的面積 
}

int main()
{
	cout<<"請輸入圓形的半徑radius:";
	double radius=0; //初始化半徑 
	cin>>radius;     //輸入半徑 
	cout<<"該圓的面積是:"<<Area_circle(radius)<<endl;
	return 0;
} 

運行結果如下:
在這裏插入圖片描述

(3) 函數聲明

函數聲明會告訴編譯器函數名稱及如何調用函數。函數聲明包括以下幾個部分:

return_type function_name(parameter list);//函數聲明

很容易看出,函數的聲明和上面函數定義中的函數頭一致,不同的是,句末要加上一個分號。因此,針對上面計算圓形的面積的例子,Area_circle()函數聲明形式如下:

double Area_circle(double r);

在函數聲明中,參數的名稱並不重要,只有參數的類型是必需的,因此下面也是有效的聲明:

double Area_circle(double);

函數聲明最常用的兩種情形:

  1. 若函數實現在mian()函數之後,當main()中需要調用該函數時,我們需要程序中main()前的位置提前聲明該函數。我們還是以計算圓形的面積爲例:
#include<iostream>
using namespace std;

const double Pi =3.14;
double Area_circle(double r); //函數聲明 

int main()
{
	cout<<"請輸入圓形的半徑radius:";
	double radius=0; //初始化半徑 
	cin>>radius;     //輸入半徑 
	cout<<"該圓的面積是:"<<Area_circle(radius)<<endl;
	return 0;
} 

double Area_circle(double r)
{
	return Pi*r*r;  //返回圓的面積 
}
  1. 當你在一個源文件中定義函數且在另一個文件中調用函數時,函數聲明是必需的。在這種情況下,你應該在調用函數的文件頂部聲明函數。

(4) 函數調用

創建 C++ 函數時,會定義函數做什麼,然後通過調用函數來完成已定義的任務。
調用函數時,傳遞所需參數,如果函數返回一個值,則可以存儲該函數返回的值。我們還是以計算圓形的面積爲例:

#include<iostream>
using namespace std;

const double Pi =3.14;
double Area_circle(double r); //函數聲明 

int main()
{
	cout<<"請輸入圓形的半徑radius:";
	double radius=0,area=0; //初始化半徑 、面積 
	cin>>radius;     //輸入半徑 
	area=Area_circle(radius);  //將函數的返回值給area 
	cout<<"該圓的面積是:"<<area<<endl;
	return 0;
} 

double Area_circle(double r)
{
	double S=Pi*r*r;  //就算圓的面積 
	return S;  //返回面積S 
}

運行結果:
在這裏插入圖片描述

(5) 形參與實參

如果函數要使用參數,則必須聲明接受參數值的變量。這些變量稱爲函數的形式參數。
形式參數就像函數內的其他局部變量,在進入函數時被創建,退出函數時被銷燬
比如,前面講到的函數定義和函數聲明中的參數列表中的變量就是形參
當調用函數時,我們需要用到實參。在調用函數的過程中,編譯器會自動將實參傳遞給形參,然後執行函數體。

2. 帶默認值的參數

在前面計算圓形的面積是例子中,我們將Pi聲明爲常量,因此後面就不能對其進行修改了。那麼,當我們希望得到更高或更低的精度時,就不能爲力了。爲了解決這種問題,我們可以給函數Area_circle()新增一個表示Pi的參數,並將其設置爲默認值。比如:

double Area_circle(double r, double Pi=3.14);

注意,第二個參數Pi的默認值是3.14。對調用者來說,這個參數是可選的,因此仍可使用下面的語句來調用Area_circle():

Area_circle(radius); //這裏省略了第二個參數,因此將使用默認值Pi=3.14

如果,我們想得到更高的精度。在調用函數時,可以提供Pi的值,指定要實際要用的Pi值。指定的Pi值會覆蓋默認值。比如:

Area_circle(radius, 3.1416); //指定Pi=3.1416,替代原來的默認值

下面,仍以計算圓形的面積爲例,演示如何編寫包含默認值的函數。

#include<iostream>
using namespace std;

double Area_circle(double r, double Pi=3.14); //函數聲明 
int main()
{
	cout<<"請輸入圓形的半徑radius:";
	double radius=0,area=0; //初始化半徑 、面積 
	cin>>radius;     //輸入半徑 
	area=Area_circle(radius);  //將函數的返回值給area 
	cout<<"使用默認值Pi,該圓的面積是:"<<area<<endl;
	
	area=Area_circle(radius, 3.1416);
	cout<<"指定Pi=3.1416後,該圓的面積是:"<<area<<endl;
	return 0;
} 

double Area_circle(double r, double Pi)
{
	double S=Pi*r*r;  //就算圓的面積 
	return S;  //返回面積S 
}

運行結果:
在這裏插入圖片描述

3. 遞歸函數

在有些情況下,可讓函數調用它自己,這樣的函數稱爲遞歸函數。遞歸函數必須有明確的退出條件,滿足這種條件後,函數將返回,而不再調用自己。
在計算斐波那契數列時,遞歸函數很有用。
Fibonacci數列的遞推公式爲:Fn=Fn-1+Fn-2,其中F1=F2=1。
使用遞歸函數實現如下:

#include <iostream>
using namespace std;

int Fibonacci(int n)   //Fibonacci數列函數 
{
	if(n==1||n==2)
		return 1;
	else
		return Fibonacci(n-1)+Fibonacci(n-2);
}

int main()
{
	int n=0;
	cin>>n;
	cout<<Fibonacci(n);  //輸出Fibonacci數列第n個數 
	return 0;
}

4. 使用函數處理不同類型的數據

並不是每次只能給函數傳遞一個值,還可以將數組等傳遞給函數。這樣可在函數中操縱更多的數據和參數。

(1) 函數重載

名稱和返回類型相同,但是參數不同的函數被稱爲重載函數
在程序中,如果需要使用不同的參數調用具有特定名稱和返回類型的函數,重載函數將很實用。
下面舉個例子,計算圓和圓柱的面積。計算圓面積的函數需要一個參數——半徑r,而計算圓柱面積的函數還需要一個參數——高度h。這兩個函數需要返回的數據類型相同,都是面積。在C++中,我們可以定義兩個重載的函數,它們都叫Area,返回類型都是double,但第一個函數僅接受r爲參數,第二個接受r、h作爲參數。

#include<iostream>
using namespace std;

const double Pi=3.14;
double Area(double r);
double Area(double r, double h);
int main()
{
	int r=0,h=0;
	cout<<"輸入圓柱體的半徑r和高h:";
	cin>>r>>h;
	cout<<"圓的面積是:"<<Area(r)<<endl;
	cout<<"圓柱的表面積是:"<<Area(r,h);
	return 0; 
}

double Area(double r) //計算圓的面積 
{
	return Pi*r*r; 
}

double Area(double r, double h) //計算圓柱的表面積 
{
	return 2*Area(r)+2*Pi*r*h;
}

運行結果:
在這裏插入圖片描述

(2) 將數組傳遞給函數

顯示一個數組的函數類似於下面這樣:

//第一個參數表示輸入的是數組,第二個參數指出了數組的長度,以免使用數組時越界
void ShowArr(int NumArr[], int length);

下面,舉例顯示整型數組和字符數組中的每個元素:

#include<iostream>
using namespace std;

void ShowArr(int NumArr[], int length)
{
	for(int i=0;i<length;i++)
		cout<<NumArr[i]<<" ";
} 

void ShowArr(char CharArr[], int length)
{
	for(int i=0;i<length;i++)
		cout<<CharArr[i]<<" ";
}

int main()
{
	int Numbers[5]={0,1,2,3,4};
	ShowArr(Numbers, 5);
	cout<<endl;
	char Characters[6]={'H','E','L','L','O','\0'};
	ShowArr(Characters,6);
	return 0;
}

運行結果:
在這裏插入圖片描述

(3) 按引用傳遞參數

有時候,你希望函數修改的變量能在其外部也可用,爲此,可將形參的類型聲明爲引用,下面以Area()函數計算面積爲例,以參數的方式按引用返回它:

void Area(double r, double& result)
{
	result=Pi*r*r;
}

其中符號&,它告訴編譯器,不要將第二個實參複製給函數,而將指向該實參的引用傳遞給函數
因此,該函數的返回類型是void,因爲該函數不再通過返回值提供計算得到的面積,而是按引用以輸出參數的方式提供它。
下面顯示如何按引用返回圓的面積:

#include<iostream>
using namespace std;

const double Pi=3.14;
void Area(double r, double& result)
{
	result=Pi*r*r;
}

int main()
{
	cout<<"輸入半徑radius:";
	double radius=0;
	cin>>radius;
	double GetResult=0;
	Area(radius,GetResult);
	cout<<"圓的面積是:"<<GetResult<<endl;
	return 0;
}

運行結果:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章