# 模組化程式設計
編寫一個規模較大的程式,可以將其依功能劃分為多個獨立的模組。
每個模組由一個函式實現。
好處:
- 程序開發更容易控制
- 利於軟體重用
- 避免重複的程式碼
- 容易調適及維護
# 主函式 main()
- C++ 程式僅有一個主函式構成
- 可以由多個子函式組成
- 程式的執行順序:總是從 main 函式開始執行,其中可以調用其他的子函式
# 庫函式 (標準函式)
由系統提供,可以直接使用,但需包含相應的頭文件 (Headers)。如:
#include<iostream> // 標準 輸入 / 輸出 函式 | |
#include<cmath> // 數學庫函式 | |
#include<cstring> // 字串處理函式 |
# 自定義函式
程式的主要邏輯,也就是下半部會介紹到的重要工具!!
# 函式的定義
<函式值型態> <函式名> (<形式參數表>) // 函式頭 | |
{ | |
<語句序列> // 函數體 | |
} |
# 函式值型態
即函式的返回值型態
- 返回簡單型態,如:
int
、float
、bool
等 - 返回結構型態
- 返回指標型態
- 返回引用型態
如果沒有任何返回值,返回值型態應標記 void
, void
型態稱為無型態或空型態。
# 形式參數表
即形參表,函數的參數表用於實現函數間的數據關係。
- 說明格式:
<型態1> <形參1>,<型態2> <形參2>, ... ,<型態n> <形參n>
- 定義函式時需考慮設置的形參,形參的個數即型態根據需要設定。
也可以沒有參數,稱為無參函式。 - 形參可以接收主調函式傳遞的實參值。
在函式中對形參進行處理,並將處理結果反回到主調函式。 - 形參是在函數調用時分配存儲空間,同時接收實參的值。
當函式執行結束後,系統將自動是放形參分配的存儲空間。
因此,形參屬於函式的局部變數,只能在該函式中使用。 - 當形參為引用型態或指標型態時,利用形參不僅可以訪問時參的值,還可以改變實參本身的值。
# 函式體
由 { }
刮起來的語句序列構成,是實現函式功能的主體。
- 函式的編寫過程類似於主函式
- 在函式中可以調用其他函式
- 在函式體中,使用
return
返回函式執行的結果。
return <表達式>; // 其中表達式形態需與函式返回值的型態一致 |
- 對於無返回的函式,也可以使用
return;
將控制返回主調函式。
在一個函式中允許出現多個 return
語句,但在函式執行期間只能有一個語句起作用。
在函數體的最後一個位置,一個無返回值的 return;
語句可以省略。(有點廢話)
# 函式的宣告
- 在 C++ 中,程序編譯的單位是源程序文件 (即源文件),一個由多個函式構成的程序可以組織存放在一個或多個源文件中。
- 在源文件中,函式之間的排列順序沒有固定的要求,但要滿足 先定義後使用 的這個準則。
- 對於標準庫函式的使用,在程序開頭使用
#include
命令將所需的頭文件包含進來。 - 對於自訂義的函式,需要在調用之前先定義,不然就是在調用之前做函式宣告。
函式宣告是指在函式被調用前,對函式的型態、名稱以及參數等信息所作說明。
<型態名> <函式名>(<型態1> <形參1>, <型態2> <形參2>,...); | |
// 或者是 | |
<型態名> <函式名>(<型態1>, <型態2>, ...); // 省略了形參 |
在形式上就是在函式的首部後加分號 ;
構成。
函式宣告說明了函式所採用的形式,稱為函式原型。
#include <iostream> | |
#include <cmath> | |
using namespace std; | |
int main() | |
{ | |
double Area(double a, double b, double c); | |
// 或者 | |
// double Area(double, double, double); | |
double a,b,c; | |
cout<<"請輸入邊長:"<<endl; | |
cin>>a>>b>>c; | |
cout<<"面積為:"<<Area(a,b,c)<<endl; | |
return 0; | |
} | |
double Area(double a, double b, double c) | |
{ | |
double p,s; | |
s=(a+b+c)/2; | |
p=sqrt(s*(s-a)*(s-b)*(s-c)); | |
return p; // 返回函式的值 | |
} |
# 函式的調用
函式定義後,並不能自行執行,必須通過函式調用來實現函式的功能。
函式調用,即控制執行某個函式。
C++ 中,主函式可以調用其他子函式,而其他函式之間也可以相互調用。
# 一般格式
<函式名>(<實際參數表>) // 有參調用 | |
// 或 | |
<函式名>() // 無參調用 |
<函式名>
為要使用的函式的名字<實際參數表>
是以逗號分隔的實參數列表,必須方在括號中間。<實參表>
和<形參表>
中的個數、型態需保持一致。- 當調用無參函式時,函式名面的括號不可以省。
# 實參的幾種形式
形參為簡單型態變數,對應的實參可以是 常數、變數及表達式。
形參為陣列,對應的實參為陣列 (名)。
形參為結構型態,對應的實參為結構型態變數。
調用以之三邊長求三角形面積的函式 Area
double Area(double,double,double); // 變數宣告 | |
cout<<Area(4.0,5.0,6.0)<<endl; // 常數作實參 | |
cout<<Area(a,b,c)<<endl; // 變數作實參 | |
cout<<Area(a+1,b+1,c+2)<<endl; // 表達式作實參 |
函式調用出現在表達式中 (適於有反為值得函式調用形式)
如:函式 max()
求兩數的最大值。函式的原型為:
float max(float x,float y); |
該函式友返回值,調用時應出現在表達式中。
c=max(a,b); // 函式調用出現在賦值運算子的右表達式中 | |
d=max(c,max(a,b));// 函式調用同時出現在實參表達式中 | |
cout<<max(a,b)<<endl;// 輸出一個函式值 |
# 參數的傳遞
# 值傳遞
調用時,將實參的值傳遞給對應的形參
在傳遞過程中,改變形參的不會改變實參的值。
- 好處:
減少函數之間的數據依賴,增強了函式自身的獨立性。 - 注意:
函數的形參宣告為簡單型態或結構型態變數,實參與形參將採用值方式傳遞。
void swap(int x, int y) | |
{ | |
int tmp; | |
tmp = x; | |
x = y; | |
y = tmp; | |
} | |
int main() | |
{ | |
int a = 1, b = 2; | |
cout << "Before exchange:a= " << a << ",b= " << b << endl; | |
// a=1, b=2 | |
swap(a, b); // 獨立語句調用 | |
cout << "After exchange:a= " << a << ",b= " << b << endl; | |
//a=1, b=2 (沒有交換) | |
return 0; | |
} |
調用前實參 a、b 有自己的儲存空間,並有初值。
調用函式時,為形參的 x、y 分配儲存空間,並接收實參的值。
返回到主函式,這時實參 a 和 b 的值沒有改變。
函式中,是對 x、y 值進行交換。
執行結束後,x、y 值會自然釋放。
# 引用傳遞
引用是一種特殊的變數,他被認為是一個變數的別名
# 引用的定義
<資料型態> &<引用名> = <目標變數名>; |
&
為引用 (變數) 的標誌符號, <引用名>
是一個標識符。<資料型態>
為 <目標變數>
的型態
int a , &b = a; | |
//a 是一個整數型變數,b 是一個整數型變數 a 的引用 | |
// 即 b 是 a 變數的別名 | |
// 這時,使用 a 與使用 b 是等價的 |
# 使用說明
- 定義一個引用,其實是為目標變數起一個別名。
- 引用並不分配獨立空間出來,他與目標變數共用其內存空間。
- 定義一個引用 (變數) 時,如果該引用不是用作函式的參數或返回值,則必須提供該引用初值 (即必須提供引用的目標變數名)
- 使用引用與使用目標變數效果是一樣的。
int main() | |
{ | |
int a=2,&b=a; | |
cout<<&a<<" "<<&b<<endl;// 輸出變數的地址 // 0x61fe14 0x61fe14 | |
cout<<a<<" "<<b<<endl; // 輸出變數的值 // 2 2 | |
return 0; | |
} |
# 引用的傳遞
- 為了要實現引用傳遞,這時函數的形參定義為引用類型變數,而對應的實參應為變數名,該變數將作為飲用的目標變數名。
- 函式調用時,作為形參的引用變數並不分配新的內存空間,它將作為實參變數的別名與其共用內存。
- 使用引用參數可以直接操作實參變變數,從而能夠實現通過修改形參的值而達到修改對應實參值的目的。
- 注意:引用作為函式形參,其引用的目標變數默認為調用該函式時對應的實參變數名,所以,在定義函式時,對於引用類型參數不必提供引用的初值。
//x,y 为引用參數,x 引用 a,y 引用 b | |
void swap(int &x, int &y) | |
{ | |
int tmp; | |
tmp = x; | |
x = y; | |
y = tmp; | |
// 交換 x,y 就是交換 a,b | |
} | |
int main() | |
{ | |
int a = 1, b = 2; | |
cout << "Before exchange:a= " << a << ",b= " << b << endl; | |
// a=1, b=2 | |
swap(a, b); // 獨立語句調用 | |
cout << "After exchange:a= " << a << ",b= " << b << endl; | |
// a=2, b=1 | |
return 0; | |
} |
# 指標傳遞
指標是一個特殊的變數,負責指向值的地址
現在在這裡僅大略寫出其傳遞方式以及比較
後續,會再有一篇專講指標的文章!!敬請期待
# 指標定義
<資料型態> *<指標名> = &<目標變數名>; |
*
是指標 (變數) 標識符, <指標名>
是一個標識符。&
在這裡是位址運算子, <資料型態>
為 <目標變數>
的型態
int a , *b = &a; | |
//a 是一個整數型變數,b 是一個指標其指向 a 所在的位置 | |
// 這時,使用 a 與使用 *b 是等價的 |
# 使用說明 (簡易版)
指標指向一塊內存,它的內容是所指內存的地址
int main() | |
{ | |
int a=2,*b = &a; | |
cout<<&a<<" "<<b<<endl; // 輸出變數的地址 // 0x61fe14 0x61fe14 | |
cout<<a<<" "<<*b<<endl; // 輸出變數的值 // 2 2 | |
return 0; | |
} |
# 指標的傳遞
- 形參為指向實參地址的指標,當對形參的指向操作時,就相當於對實參本身進行的操作
- 注意:使用指標傳遞時,傳入的實參必須是其地址,之後再用指標當作形參去做使用
void swap(int *x, int *y) | |
{ | |
int tmp; | |
tmp = *x; | |
*x = *y; | |
*y = tmp; | |
} | |
int main() | |
{ | |
int a = 1, b = 2; | |
cout << "Before exchange a= " << a << ",b= " << b << endl; | |
swap(&a, &b); | |
cout << "After exchange a= " << a << ",b= " << b << endl; | |
return 0; | |
} |
# 指標和引用的異同
- 指標是一個實體,而引用僅是個別名。
- 引用只能在定義時被初始化一次,之後不可變;指標可變;引用 “從一而終”,指標可以 “見異思遷”。
- 引用沒有 const,指針有 const,const 的指針不可變。
- 引用不能為空,必須在定義的時候同時進行初始化。指針可以為空,任何時候初始化都可。
- 指標和引用的自增 (++) 運算意義不一樣。
- 引用是類型安全的,而指標不是 (引用比指針多了類型檢查)
# 為形參加入默認值
C++ 語言允許在函數定義時為形參指定默認參數值。
這樣,在函數調用時,如果沒有提供實參,則形參自動使用其默認值。
void f(int x=0,int y=0); // 形参的默認值為 0 | |
f();// 為提供實參,形參 x,y 使用默認值 0 | |
f(2,4);// 形參 x,y 将使用實參的值 2 和 4 | |
f(1);// 形參 x 接收 1,而 y 使用 0 |
可以從右至左的連續若干個形參設置默認值
void f(int i,int j=2,int k=3);// 正確 | |
void f(int i,int j,int k=3); // 正確 | |
void f(int i=1,int j,int k=3);// 錯誤 | |
void f(int i=1,int j,int k);// 錯誤 |
# 陣列做為函式參數
# 一維陣列傳遞
<型態> <陣列名>[] |
- 其中,
[]
中可以省略陣列的長度值。 (可認為形參陣列與實參陣列長度相同) - 對應的實參應為同型態的一維數組名。 (僅用數組名)
- 為了使函式知道需要處理的陣列元素的個數,通常給函數再傳遞一個表示元素個數的整數形。
# 例子:元素和
一維陣列名作為函數的參數。編寫函數,計算一個整型數組中從第 m 個元素(m 從 0 開始)開始的 n 個元素之和。
函式設計:
- 函數原型: int fun (int b [],int m,int n);
- 功能:計算數組 b 中從第 m 個元素開始的 n 個元素之和。
主函數設計:
定義並初始化一個整型數組 a。- 測試 1: fun (a,0,10);// 求從第 0 個元素開始的 10 個元素之和
- 測試 2: fun (a,3,5); // 求從第 3 個元素開始的 5 個元素之和
int fun(int b[],int m,int n) | |
{ | |
int i,s=0; | |
for(i=m;i<m+n;i++) | |
s=s+b[i]; | |
return s; | |
} | |
int main() | |
{ | |
int x,a[]={0,1,2,3,4,5,6,7,8,9}; | |
x=fun(a,0,10); | |
cout<<x<<endl; | |
x=fun(a,3,5); | |
cout<<x<<endl; | |
return 0; | |
} |
# 二維陣列傳遞
<資料型態> <陣列名>[][<列名>] |
其中, <列數>
為常數,不能省略,行數可缺省
調用時的實參應為同形態的二維陣列名
且用作時參的二維陣列,其列數跟形參中的 <列數>
須一致
# 例子:矩陣轉置
二維陣列名作參數。編寫一個函數,將 N 階方陣轉置(N<10)
- 函數設計
void transmat(int a[][10],int n); | |
// 對 a 數組中前 n 行 n 列矩陣元素轉置 |
- 主函數設計
- 定義一個 10 行 10 列的大數組 x,元素類型為整型;
- 鍵盤輸入一個整數 n (n<10);
- 鍵盤輸入一個 n×n 的方陣數據,並存放到 x 數組的前 n 行 n 列元素中。
- 函數調用語句為: transmat (x,n);
- 按 n 行 n 列輸出轉置矩陣。
void tranmat (int a[][10],int n) | |
{ | |
int t; | |
for(int i=0;i<n-1;i++) { | |
for(int j=i;j<n;j++) | |
{ | |
t=a[i][j]; | |
a[i][j]=a[j][i]; | |
a[j][i]=t; | |
} | |
} | |
} | |
int main() { | |
int x[10][10],n; | |
cout<<"輸入n(n<10):"; | |
cin>>n; | |
cout<<"輸入"<<n<<"行"<<n<<"列元素:"<<endl; | |
for(int i=0;i<n;i++) { | |
for(int j=0;j<n;j++) { | |
cin>>x[i][j]; | |
} | |
} | |
tranmat(x,n); | |
cout<<"轉置置矩阵结果如下:"<<endl; | |
for(int i=0;i<n;i++) { | |
for(int j=0;j<n;j++) { | |
cout<<x[i][j]<<" "; | |
} | |
cout<<endl; | |
} | |
} |
# 結構變數做函式參數
實參為結構類型變數
行參為同類型的結構變數
傳遞方式為值傳遞
// 定義一個結構型態 | |
struct student | |
{ | |
int stno; | |
char name[20]; | |
int age; | |
}; | |
void print(student s) // 輸出 | |
{ | |
cout<<s.stno<<endl; | |
cout<<s.name<<endl; | |
cout<<s.age<<endl; | |
} | |
// 主函式 | |
int main() | |
{ | |
student stu={1001, "Li" ,19}; | |
print(stu); // 實參為結構型態 | |
return 0; | |
} |