C++学习笔记5[函数]
C++學習目錄鏈接:
C++學習筆記目錄鏈接(持續更新中)
文章目錄
- 一、函數概述
- 1.函數的定義
- 2.函數的聲明
- 二、函數參數及其返回值
- 1.返回值
- 2.空函數
- 3.形參和實參
- 4.默認參數
- 5.可變參數
- 三、函數調用
- 1.傳值調用
- 2.嵌套調用
- 3.遞歸調用
- 四、變量作用域
- 五、重載函數
- 六、內聯函數
- 七、變量的存儲類別
- 1.auto變量
- 2.static變量
- 3.register變量
- 4.extern變量
- 總結
一、函數概述
1.函數的定義
????函數就是能夠實現特定功能的程序模塊,它可以是只有一條語句的簡單函數, 也可以是包含許多子函數的復雜函數;函數有別人寫好的存放在庫里的庫函數,也有開發人員自己寫的自定義函數:函數根據功能可以分為字符函數、日期函數、數學函數、圖形函數、內存函數等。 一個程序可以只有一個主函數,但不可以沒有函數。
????函數的定義形式一般如下:
類型標識符 ??函數名(形式參數列表)
{
變量的聲明
語句
}
????類型標識符:用來標識函數的返回值類型,可以根據函數的返回值判斷函數的執行情況,通過返回值也可以獲取想要的數據。類型標識符可以是整型、字符型、指針型、對象的數據類型。
????形式參數列表:由各種類型變量組成的列表,各參數之間用逗號間隔,在進行函數調用時,主調函數對變量進行賦值。
????形式參數列表可以為空,這樣就定義了不需要參數的函數。例如:
2.函數的聲明
????調用一個函數前必須先聲明函數的返回值類型和參數類型。例如:
int SetIndex(int i);
????函數聲明被稱為函數原型,函數聲明時可以省略變量名。例如:
;int SetIndex(int);
????下面通過實例來介紹函數的定義、聲明、調用
????下面兩種代碼都可以執行,可以看出,如果函數定義放在主函數前面,則函數可以不聲明,直接調用。如果函數定義在主函數后面,則函數調用前必須聲明。 為了避免錯誤,建議調用函數前都先聲明下。
二、函數參數及其返回值
1.返回值
????函數的返回值是指函數被調用之后,執行函數體中的程序段所取得的并返回給主調函數的值,函數的返回值通過returm語句返回給主調函數。return 語句的一般形式如下:
return(表達式);
關于返回值的說明:
- (1)函數返回值的類型和函數定義中函數的類型標識符應保持一致。 如果兩者不一致,則以函數類型為準,自動進行類型轉換。
- (2)如函數值為整型,在函數定義時可以省去類型標識符。
- (3)在函數中允許有多個retur語句,但每次調用只能有一個returm 語句被執行,因此只能返回一個函數值。
- (4)不返回函數值的函數,可以明確定義為“空類型”,類型標識符為“void”。例如:
- (5)類型標識符為void的函數不能進行賦值運算及值傳遞。例如:
i= Showlndex();//不能進行賦值
SetIndex(ShowIndex); //不 能進行值傳遞
2.空函數
????沒有參數和返回值,函數的作用域也為空的函數就是空函數。void setWorkSpace(){}
????調用此函數時,什么工作也不做,沒有任何實際意義。在主函數main 函數中調用setWorkSpace函數時,這個函數沒有起到任何作用。例如: .
void setWorkSpace({ }
void main()
setWorkSpace();
????空函數存在的意義是:在程序設計中往往根據需要確定若干模塊,分別由一些函數來實現。 而在第一階段只設計最基本的模塊,其他一些次要功能或錦上添花的功能則在以后需要時陸續補上。在編寫程序的開始階段,可以在將來準備擴充功能的地方寫上-個空函數,這些函數沒有開發完成,先占一個位置,以后用一個編好的函數代替它。這樣做可以使程序的結構清楚,可讀性好,以后擴充新功能方便,對程序結構影響不大。
3.形參和實參
????函數定義時如果參數列表為空,說明函數是無參函數;如果參數列表不為空,就稱為有參函數。有參函數中的參數在函數聲明和定義時被稱為“形式參數”(簡稱形參),在函數被調用時被賦予具體值,具體的值被稱為“實際參數”(簡稱實參)。。
????形參與實參的區別:
- (1)在定義函數中指定的形參,在未出現函數調用時,它們并不占用內存中的存儲單元。只有在發生函數調用時,函數的形參才被分配內存單元,在調用結束后,形參所占的內存單元也被釋放。
- (2)實參應該是確定的值。在調用時將實參的值賦給形參,如果形參是指針類型,就將地址值傳遞給形參。
- (3)實參與形參的類型應相同。
- (4)實參與形參之間是單項傳遞,只能由實參傳遞給形參,而不能由形參傳回來給實參。
- 實參與形參之間存在一個分配空間和參數值傳遞的過程,這個過程是在函數調用時發生的。C++支持引用型變量,引用型變量則沒有值傳遞的過程,這將在后文講到。
4.默認參數
????在調用有參函數時,如果經常需要傳遞同一個值到調用函數,在定義函數時,可以為參數設置一個默認值,這樣在調用函數時可以省略一些參數,此時程序將采用默認值作為函數的實際參數。
方式1
方式2
#include <iostream> using namespace std;//函數定義語句 void ShowMessage(const char* pchData="yudengwu") {cout<<pchData<<endl; } //主函數 void main() {ShowMessage();//函數調用,使用默認參數ShowMessage("yudengwu123");//沒有使用默認參數}????在定義函數默認參數時,如果函數具有多個參數,應保證默認參數出現在參數列表的右方,沒有默認值的參數出現在參數列表的
左方,即默認參數不能出現在非默認參數的左方。
5.可變參數
????庫函數printf就是一一個可變參數函數,它的參數列表會顯示“…”。 printf 函數原型格式如下:_CRTIMP int cdecl printf(const char*,…),“…”代表的含義是函數的參數是不固定的,可以傳遞一個或多個參數。對于printf函數來說,可以輸出一項信息,也可以同時輸出多項信息。例如:
printf("%d and % c",a,b);????聲明可變參數的函數和聲明普通函數一樣,只是參數列表中有一個“…”例如:
void OutputInfo(int num…)//定義可變參數函數
????對于可變參數的函數,在定義函數時需要- – 讀取用戶 傳遞的實際參數。可以使用va_ list 類型和va_ start、 va_ arg、 va_ end 3個宏讀取傳遞到函數中的參數值。使用可變參數需要引用STDARGH頭文件。下面以一個具體的實例介紹可變參數函數的定義及使用。
標準宏
//可變參數標準宏頭文件 #include "stdarg.h"//申明va_list數據類型變量pvar,該變量訪問變長參數列表中的參數。 va_list pvar;//宏va_start初始化變長參數列表。pvar是va_list型變量,記載列表中的參數信息。 //parmN是省略號"..."前的一個參數名,va_start根據此參數,判斷參數列表的起始位置。 va_start(pvar, parmN);//獲取變長參數列表中參數的值。pvar是va_list型變量,type為參數值的類型,也是宏va_arg返回數值的類型。 //宏va_arg執行完畢后自動更改對象pvar,將其指向下一個參數。 va_arg(pvar, type);//關閉本次對變長參數列表的訪問。 va_end(pvar);模板
#include <stdarg.h> function (parmN, ...) {va_list pvar; va_start (pvar, parmN);while(...){...f = va_arg (pvar, type);...}va_end (pvar); }實例
#include <iostream> #include "stdarg.h" using namespace std;int sum(int count, ...) {int sum_value=0;va_list args;va_start(args,count);while(count--){sum_value+=va_arg(args,int);}va_end(args);return sum_value; }int main() {cout<<sum(5,1,2,3,4,5);//輸出15,第一個5表示個數 }三、函數調用
????聲明完函數后就需要在源代碼中調用該函數。整個函數的調用過程被稱為函數調用。標準C++是一種強制類型檢查的語言,在調用函數前,必須把函數的參數類型和返回值類型告知編譯。函數調用的一些說明:
- (1)首先被調用的函數必須是已經存在的函數(是庫函數或用戶自己定義的函數)。
- (2)如果使用庫函數,還需要將庫函數對應的頭文件引入,這需要使用預編譯指令#include。
- (3)如果使用用戶自定義函數,一般還應該在主調函數中對被調用的函數作聲明。
1.傳值調用
????主調函數和被調用函數之間有數據傳遞關系,換句話說,主調函數將實參數值復制給被調用函數的形參處,這種調用方式被稱為傳值調用。如果傳遞的實參是結構體對象,值傳遞方式的效率是低下的,可以通過傳指針或使用變量的引用來替換傳值調用。傳值調用是函數調用的基本方式。
#include <iostream> using namespace std; void swap(int a,int b) {int temp;temp=a;a=b;b=temp; }void main() {int a=1,b=2;if (a<b){swap(a,b);}cout<<a<<endl;cout<<b<<endl;}????程序本意是想實現當a小于b時交換a和b的值,但結果并沒有實現,主要原因是調用swap函數時復制了變量a和b的值,而并非變量本身。
應用指針交換
#include <iostream> using namespace std; void swap(int *a,int *b) {int tmp;tmp=*a;*a=*b;*b=tmp; }void main() {int a=1,b=2;if (a<b){swap(a,b);}cout<<a<<endl;cout<<b<<endl;}????函數調用中發生的數據傳遞是單向的,只能把實參的值傳遞給形參,在函數調用過程中,形參的值發生改變,實參的值不會發生變化。
2.嵌套調用
????在自定義函數中調用其他自定義函數,這種調用方式稱為嵌套調用。例如:
#include <iostream> using namespace std; void showMessage() {cout<<"余登武"<<endl; } void display() { showMessage(); }void main() { display(); }????在函數嵌套調用時要注意,不要在函數體內定義函數,如下代碼便是錯誤的:
#include <iostream> using namespace std; void showMessage() {cout<<"余登武"<<endl; }void main() { void display() { showMessage(); } }3.遞歸調用
????直接或間接調用自己的函數被稱為遞歸函數(recursive funciton)。使用遞歸方法解決問題的特點是:問題描述清楚、代碼可讀性強、結構清晰,代碼量比使用非遞歸方法少。缺點是遞歸程序的運行效率比較低,無論是從時間角度還是從空間角度都比非遞歸程序差。對于時間復雜度和空間復雜度要求較高的程序,使用遞歸函數調用要慎重。遞歸函數必須定義一個停 止條件,否則函數將永遠遞歸下去。
遞歸求和
#include <iostream> using namespace std;int cal_sum(const int n) {if (n == 1){return 1;}return n + cal_sum(n - 1); }int main() {int num = 0;cin >> num;int sum = 0;sum = cal_sum(num);cout << "the sum is " << sum << endl;system("pause");return 0; }四、變量作用域
????根據變量聲明的位置可以將變量分為局部變量及全局變量,在函數體內定義的變量稱為局部變量,在函數體外定義的變量稱為全局變量。例如:
#include <iostream> using namespace std;int iTotalCount;//全局變量int GetCount(); //函數聲明void main() {int iTotalCount=100;//局部變量cout<<iTotalCount<<endl;cout<<GetCount()<<endl;//函數調用}//函數定義 int GetCount() {iTotalCount=200;return iTotalCount; }????變量都有它的生命期,全局變量在程序開始時創建并分配空間,在程序結束時釋放內存并銷毀;局部變量是在函數調用時創建,并在棧中分配內存,在函數調用結束后銷毀并釋放。
五、重載函數
????定義同名的變量,程序會編譯出錯,定義同名的函數也會帶來沖突的問題,但C++中使用了名字重組的技術,通過函數的參數類型來識別函數,所謂重載函數就是指多個函數具有相同的函數標識符,
但參數類型或參數個數不同。函數調用時,編譯器以參數的類型及個數來區分調用哪個函數。下面的實例定義了重載函數。
六、內聯函數
????通過inline關鍵字可以把函數定義為內聯函數,編譯器會在每個調用該函數的地方展開一個函數的副本。
#include <iostream> using namespace std;//定義一個內斂函數 inline int Add(int x,int y) {return x+y; }void main() {int Arr=Add(5,2);//調用cout<<Arr<<endl;}上面的執行代碼等于:
#include <iostream> using namespace std;//定義一個內斂函數 inline int Add(int x,int y) {return x+y; }void main() {int a=5;int b=2;int Arr=a+b;cout<<Arr<<endl;}????使用內聯函數可以減少函數調用帶來的開銷(在程序所在文件內移動指針尋找調用函數地址帶來的開銷),但它只是一種解決方案,編譯器可以忽略內聯的聲明。
????應該在函數實現代碼很簡短或者調用該函數次數相對較少的情況下將函數定義為內聯函數,一個遞歸函數不能在調用點完全展開,一個一千行代碼的函數也不大可能在調用點展開,內聯函數只能在
優化程序時使用。在抽象數據類設計中,內聯函數對支持信息隱藏起著主要作用。
????如果某個內聯函數要作為外部全局函數,即它將被多個源代碼文件使用,那么就把它定義在頭文件里,在每個調用該內聯函數的源文件中包含該頭文件,這種方法保證對每個內聯函數只有一個定義,防止在程序的生命期中引起無意的不匹配。
七、變量的存儲類別
????存儲類別是變量的屬性之一,C++語言中定義了4種變量的存儲類別,分別是auto變量、static 變量、register 變量和exterm變量。變量存儲方式不同會使變量的生存期不同,生存期表示了變量存在的時間。生存期和變量作用域是從時間和空間這兩個不同的角度來描述變量的特性。
????靜態存儲變量通常是在變量定義時就分配固定的存儲單元并一直保持不變,直至整個程序結束。前面講過的全局變量即屬于此類存儲方式,它們存放在靜態存儲區中。動態存儲變量是在程序執行過程中使用它時才分配存儲單元,使用完畢立即將該存儲單元釋放。前面講過的函數的形式參數,在函數定義時并不給形參分配存儲單元,只是在函數被調用時才予以分配,調用函數完畢立即釋放,此類變量存放在動態存儲區中。從以上分析可知,靜態存儲變量是一直存在的,而動態存儲變量則時而存在時而消失。
1.auto變量
????這種存儲類型是C ++語言程序中默認的存儲類型。函數內未加存儲類型說明的變量均視為自動變量,也就是說自動變量可省去關鍵字auto。例如:
int a,b,c;等價于
auto int a,b,c;????自動變量有如下特點:
- (1)自動變量的作用域僅限于定義該變量的個體內。在函數中定義的自動變量,只在該函數內有效;在復合語句中定義的自動變量,只在該復合語句中有效。
- (2)自動變量屬于動態存儲方式,變量分配的內存是在棧中,當函數調用結束后,自動變量的值會被釋放。同樣,在復合語句中定義的自動變量,在退出復合語句后也不能再使用,否則將引起錯誤。
- (3)由于自動變量的作用域和生存期都局限于定義它的個體內(函數或復合語句內),因此不同的個體中允許使用同名的變量而不會混淆。即使在函數內定義的自動變量也可與該函數內部的復合語句中定義的自動變量同名。
2.static變量
????在聲明變量時加關鍵字static,可以將變量聲明為靜態變量。靜態局部變量的值在函數調用結束后不消失,靜態全局變量只能在本源文件中使用。例如下面的代碼聲明變量為靜態變量:
static int a,b; static float c,d;????靜態變量屬于靜態存儲方式,它具有以下特點:
- (1)靜態變量在函數內定義,在程序退出時釋放,在程序整個運行期間都不釋放,也就是說它的生存期為整個源程序。
- (2)靜態變量的作用域與自動變量相同,在函數內定義就在函數內使用,盡管該變量還繼續存在,但不能使用它,如再次調用定義它的函數時,它又可繼續使用。
- (3)編譯器會為靜態局部變量賦予0值。
如果去掉static
/*求累加和。*/#include <iostream> using namespace std;int Add(int x) { int n=0;//定義n為int 型變量 n=n+x; return n; }void main() {int i,j,sum;cout<<"請輸入一個數:"<<endl;cin>>j;cout<<"輸入的數為:"<<j<<endl;for(i=0;i<=j;i++){sum=Add(i);cout<<"sum is:"<<sum<<endl;} }3.register變量
????通常變量的值存放在內存中,當對一個變量頻繁讀寫時,需要反復訪問內存儲器,此時將花費大量的存取時間。為了提高效率,C++語言 可以將變量聲明為寄存器變量,這種變量將局部變量的值存
放在CPU中的寄存器中,使用時不需要訪問內存,而直接從寄存器中讀寫。寄存器變量的聲明符是register.
對寄存器變量的說明:
- (1)寄存器變量屬于動態存儲方式。凡需要采用靜態存儲方式的變量不能定義為寄存器變量。
- (2)編譯程序會自動決定哪個變量使用寄存器存儲。register 可以起到程序優化的作用。
4.extern變量
????在-一個源文件中定義的變量和函數只能被本源文件中的函數調用,一個C++程序中會有許多源文件,那么如何使用非本源文件中的全局變量呢? C++t提供了exterm 關鍵字來解決這個問題。在使用其他源文件中的全局變量時,只需要在本源文件中使用exterm關鍵字來聲明這個變量即可。例如,在3.cpp源文件中定義全局變量a、b、c, 代碼如下:
在4.cpp源文件中要使用3 .cpp源文件中的全局變量a、b、c,
代碼如下:
3.cpp,4.cpp的運行結果都為如圖
總結
本文講解了C++中的函數。
作者:電氣-余登武
總結
以上是生活随笔為你收集整理的C++学习笔记5[函数]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电气期刊论文实现:基于输电线路容量安全约
- 下一篇: C++ 常见bug记录(持续记录中)