【不是惡夢的開始,而是再度的精進。 自訂函數】
我們在程式中需要重複執行某一組指令功能時,迴圈就是最好的選擇。那麼將這一組能完成特定工作的指令,模組化成一個完整的函數,便可以隨時呼叫引用,這就是自訂函數了。
在這之前,其實我們不知不覺中已經使用過無數次的函數了,那就是主程式的入口
int main(int argc, char** argv)
{
.....
.....
........
cout << "\n美麗的新世界就從這裡開始\n";
return 0;
}
就像是使用變數一樣,想要使用自訂函數時,也必須要宣告函數原型,其中包括傳回型態、傳入函數的引數型態,宣告格式如下:
傳回值型態 函數名稱(引數型態1, 引數型態2, ....);
int add (int, int, .....); // 回傳值為整數型態,引數為整數型態
void symbol (int, char, ....); // 無回傳值,引數有整數型態與字元型態
void symbol (void); // 無回傳值,無引數
自訂函數名稱的命名和變數的命名規則相同,都不能使用到C++的關鍵字,也都建議以有意義的名稱為函數命名。
一般來說,main()函數放在程式的一開始處,自訂函數在main()函數後面,就需要宣告自訂函數原型。
如果把自訂函數放在main()函數的前面,則不需要宣告自訂還數的原型。
自訂函數的寫法和main()函數的寫法類似,格式如下:
傳回值型態 函數名稱(引數型態1, 引數型態2, ....)
{
變數宣告;
敘述主體;
return 運算式;
}
呼叫函數的方式有兩種,如果有傳回值時,則指定某個變數來接收,格式如下:
變數 = 函數名稱(引數);
例:
#include <iostream>
using namespace std;
int add(int initial);
int main(int argc, char** argv)
{
int ai = 5;
cout << "main() 呼叫 add()前 ai = " << ai << "\n\n";
ai = add(ai); // 用變數來接收函數的回傳值
cout << "main() 呼叫 add()後 ai = " << ai ;
return 0;
}
int add(int bi)
{
int resulti = 0;
resulti = bi + 8;
return resulti;
}
執行結果:
main() 呼叫 add()前 ai = 5
main() 呼叫 add()後 ai = 13
函數如果沒有回傳值時,則直接呼叫函數,格式如下:
函數名稱(引數);
例:
#include <iostream>
using namespace std;
void add(int initial);
int main(int argc, char** argv)
{
int ai = 5;
cout << "main() 呼叫 add()前 ai = " << ai << "\n";
add(ai);
cout << "main() 呼叫 add()後 ai = " << ai ;
return 0;
}
void add(int ai)
{
ai += 8;
cout << "add() ai = " << ai << "\n";
return;
}
執行結果:
main() 呼叫 add()前 ai = 5
add() ai = 13
main() 呼叫 add()後 ai = 5
上例示範 add(ai); 呼叫函數,另外聊一下區域變數。
在add()函數的大括號{}內並沒有宣告變數 ai,但卻可以直接作加法運算 ai += 8;,因為變數ai在函數的參數就已經宣告了 add(int ai),所以無需另外再宣告一次。
在main()函數和add()函數內都有變數ai,這兩個變數ai並不是同一個變數,是兩個各自獨立的變數。只要是被大括號{}包含住的變數就是區域變數,所以在呼叫add()函數的時候,add()函數內的變數ai的值被改變了,但呼叫完add()函數後,再一次的顯示main()函數內的變數ai,仍然是5,因為add()函數只能改變自己函數內的區域變數ai的值,或更改全域變數的值,並不能該改其他函數main()內的區域變數值。
修改一下程式碼,來看看全域變數
#include <iostream>
using namespace std;
void add(int initial);
int ai = 0; // 全域變數
int main(int argc, char** argv)
{
ai = 5;
cout << "main() 呼叫 add()前 ai = " << ai << "\n";
add(ai);
cout << "main() 呼叫 add()後 ai = " << ai ;
return 0;
}
void add(int bi)
{
ai = bi + 8;
cout << "add() ai = " << ai << "\n";
return;
}
執行結果:
main() 呼叫 add()前 ai = 5
add() ai = 13
main() 呼叫 add()後 ai = 13
這次我們把 int ai = 5; 宣告在函數外面,只要不被函數的大括號{}包含住,這就是全域變數了。
全域變數的值是每個函數都可以變動更改的,所以main()函數在呼叫add()函數之前先把5設定給變數ai,這樣就改變了變數ai的值了,而呼叫了add()函數後,又把變數ai再更改一次它的值,因此第二次在main()函數又輸出一次變數ai的值時,因為變數ai已經被add()函數更改變數值,所以就和第一次輸出不一樣的值了。
另外我們調整一下全域變數的位置,再編譯一次
#include <iostream>
using namespace std;
void add(int initial);
//int ai = 0;
int main(int argc, char** argv)
{
ai = 5; // 'ai' was not declared in this scope
cout << "main() 呼叫 add()前 ai = " << ai << "\n";
add(ai);
cout << "main() 呼叫 add()後 ai = " << ai ;
return 0;
}
int ai = 0;
void add(int bi)
{
ai = bi + 8;
cout << "add() ai = " << ai << "\n";
return;
}
編譯錯誤訊息 [Error] 'ai' was not declared in this scope
在全域變數宣告位置之前的任何函數內都無法使用到該全域變數,因此編譯程式會認為main()函數內的變數ai並還沒有宣告,而在add()函數的變數ai就是宣告過的全域變數。如果你一定要在main()函數內使用ai,那麼在ai = 5; 之前要加一行 extern int ai;宣告ai為外部變數,這樣才能拓展外部變數ai的活動範圍。
正因為任何函數都有可能更改到全域變數的值,當程式有錯誤時會造成全域變數的值很難追蹤,所以必須謹慎規劃全域變數,但全域變數還是有它存在的好處。
.