寫在前面:大家好!我是【AI 菌】,一枚愛彈吉他的程序員。我
熱愛AI、熱愛分享、熱愛開源
! 這博客是我對學習的一點總結與記錄。如果您也對深度學習、機器視覺、算法、Python、C++
感興趣,可以關注我的動態,我們一起學習,一起進步~
我的博客地址爲:【AI 菌】的博客
上一篇:【C++養成計劃】控制程序流程——判斷與循環(Day5)
昨天,我們學習了C++程序中的兩大控制流程:判斷和循環。今天,我們來學習編程語言中一個很重要的知識板塊:函數。
文章目錄
1. 初識函數
一說到函數,對於編程小白,可能首先聯想到的是數學中的函數公式:。其實呢?C++函數與數學函數式子是有一些相通之處,比如,它們一般都有着輸入和輸出;函數式中的映射關係,對應到C++函數中就是一種邏輯關係。
不同的是,在C++中,函數是一組一起執行一個任務的語句。每個 C++ 程序都至少有一個函數,即主函數 main() ,並且程序從主函數處開始執行。具體可參見:【C++養成計劃】基本語法(Day2)。
(1) 爲何需要函數
其實,對於小型的應用程序來說,完全可以使用main()實現所有功能。但是當程序越來越大,越來越複雜時,若想要main()中的代碼依然保持簡潔、邏輯清晰易讀,就必須使用函數了。
函數能夠很好地劃分和組織程序的執行邏輯。通過使用函數,可以將原本複雜冗長的程序劃分爲依次調用的程序塊。
(2) 函數定義
在C++ 中,函數定義的一般形式如下:
return_type function_name(parameter list)
{
函數主體
}
由此可知,函數主要有如下4個組成部分:
- 返回類型 return_type。是指函數返回值的數據類型,一個函數可以返回一個值。有些函數只執行某些操作不返回值,那麼返回類型要設置爲viod。
- 函數名稱 function_name。就是函數的名字,由我們自己設定,在調用函數時用到。
- 參數列表 parameter list。參數就像是佔位符。當函數被調用時,你向參數傳遞一個值,這個值被稱爲實際參數。參數列表包括函數參數的類型、順序、數量。參數是可選的,也就是說,函數也可以不包含參數。
- 函數主體。是函數的主體結構,由執行一個任務的若干語句構成。
下面舉一個簡單的例子,用函數實現:計算圓形的面積
#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);
函數聲明最常用的兩種情形:
- 若函數實現在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; //返回圓的面積
}
- 當你在一個源文件中定義函數且在另一個文件中調用函數時,函數聲明是必需的。在這種情況下,你應該在調用函數的文件頂部聲明函數。
(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;
}
運行結果: