iT邦幫忙

2021 iThome 鐵人賽

DAY 13
0
Software Development

三十天內用C++寫出一個小遊戲系列 第 13

Day 13 - 函式烤肉

為什麼要用function(函式)?

通常會將statement 放在函數(function)裡面,以利之後的呼叫(invoke)。

  • Modules: 把工作分割成一個個的模組(modulariztion 模組化)
  • Debug: 方便debug
  • Consistency: 再重複使用時,可以重複呼叫

Basics of function:

架構:

Function = Header + Body

  1. Header for declaration : (宣告)

    1. Function name

    2. A list of parameters

    3. A return value

      (Input parameters → Function → a returned value)

  2. Body for definition: (定義)

    1. Statements that define the task.

函數有兩種function :

  1. System-defined 自定義

    Ex: <iostream> 、<cmath> :abs() 、<clinics>中的一些函數

  2. User-defined

    EX:

//Function_Instance_1
#include <iostream>
using namespace std;

int add(int, int); // Header
int main() // main function
{
	int c = add(10, 20);
	cout << c << "\n";
	return 0; 
}

int add(int num1, int num2) //Body 
{
	return num1 + num2;
}
  1. 在呼叫前要寫function 的header
    1. Header 的名字:add
    2. 傳什麼參數進去(input):兩個整數
    3. 回傳什麼:回傳一個整數
  2. Body :
    1. For definition

Function declaration:

To implement a function, we first declare its prototype(雛形):

*return type function name (parameter types);* 
  1. 規則跟宣告變數時差不多

  2. Parameters 可以輸入 0 1 or more個(用逗號隔開)

  3. 也可以在初始化的時候給予他們名字

    Ex:

    Int add(int num1, int num2);

    double divide(double num, double den);

  4. 如果不回傳函數的話,type 的地方就要寫 void(虛無的意思)

  5. 通常會在preprocessor 後且main function前

來宣告這個函數(declaration);在main function 後才會define(implement) 這個函數。

  1. 在function definition則需要將宣告函數的parameter的list 需要給予名字。→這些parameter就可以在這個function中使用(但也只能在這個函數中使用)

Function definition:

*return type function name (parameters)
{
	statements
}*

Function invocation

#include<iostream>
using namespace std;
int add(int, int);
void test(int);
int main()
{
	int c = add(10, 20);
	cout << c << "\n";
	return 0;
}
int add(int num1, int mun2)
{
	test(num1);
	return num1 + num2;
}
void test(int toPrint)
{
	cout << toPrint << "\n";
}

在上面這個例子

  1. 【main function】: main function 出發,
  2. 【add function】: 在add 中得到了 num1(10) 還有 num2(10)
  3. 【test function】: 接著在test function 裡面得到 toPrint 是 10 (add 把 10 丟進去)

其實整個流程,就像是把 int c = add(10, 20) 可以想成⇒ int c = 30這樣。

由時候也可以直接做 definition

像是這樣:

int add(int num1, num2)
{
	return num1 + num2;
}

int main()
{
	// it's fine
	int c = add(10, 20);
	cout << c << "n";
	return 0;
}

但是,在使用一個函式前,一定要先 declare 它

像是這樣:

void a()
{
	// error !!
	b(); 
}
void b()
{
	;
}

int main ()
{
	// it is able to work
	a();
	b();
	return 0;
}

中的 a() 在呼叫 b() 的這個狀況,會發生 compilation error。

這個情形,其實把 prototype 寫出來就可以解決了唷!

像是這樣就行了:

void a();
void b();

int main ()
{
	a();
	b();
	return 0;
}
void a()
{
	// it's fine!
	b(); 
}
void b()
{
	;
}

using function prototypes also enhances communications and maintenance.可以寫一些註解 表示 parameter 的意思 還有為什麼要有這個 function

Function parameters vs. arguments

parameter: 在 function 裡面的會被稱作為 parameters

argument : 是指從外面傳進去 function 的參數稱之。

ex:

int add(int num1, int num2) // 這裡面的兩個num1 num2就叫做 parameter
{
	return num1 + num2
}
int main()
{
	double q1 = 10.5;
	double q2 = 20.7;
	double c = add(q1, q2 - 3); // 這裡面的 q1, q2-3 就是被稱為 argument
	cout << c << endl;
	return 0;
}

在上面 q1 = 10.5, q2 - 3 = 17.7 (arguments)

所以num1 num2會分別得到 10 還有 17 (parameters)

Function argument

可以是

  • Literal
  • Variable
  • Constant variables
  • Expression

但其實,argument 的type其實無所謂,因為在function 編譯時,編譯器會自動把他 cast

Return value

在C++裡面只能return 1 or 0個變數(可以用陣列等)

如果不回傳 : 使用 void(),在裡面不會回傳任何數字

或是可以寫 return;

int max(int a, int b)
{
	if(a > b)
		return a;
	else
		return b;
}

如果是 void() 就會運行到最後一個 statement 才停止。

另外,如果 function 回傳的值如果沒有被設定,就會執行出我們意想不到的結果

int test(int);

int main()
{
	cout << test(-1);
	return 0;
}

int test(int a )
{
	if (a > 0)
		return 5;
}

在我的電腦裡面,結果會跑出1,但是我們明明沒有叫他回傳1阿,所以這樣子會做出很多意想不到的事情,也會導致很多錯誤。

coupling and cecoupling

Ex : 比大小

#include<iostream>
using namespace std;
int max (int a, int b);
int main()
{
	int n = 0, m = 0;
	cin >> n >> m;
	cout << max(n, m);
	return 0;
}
int max(int a, int b)
{
	return (a > b)? a : b;
}
#include<iostream>
using namespace std;
int max (int a, int b);
int main()
{
	int n = 0, m = 0, p = 0;
	cin >> n >> m >> p;
	cout << max(max(n, m), p);
	return 0;
}
int max(int a, int b)
{
	return (a > b)? a : b;
}

這兩者寫出來的樣子,似乎都長得一樣,

左邊是會 return 一個值 右邊是直接在 function 裡面 cout。

decoupling 的意思: 如果把兩個 函式 切分得比較開,函式的相容性會比較好(就像是這個函式可以獨立運作),像是左邊的只是回傳一個值,但是我們可以把他的值拿去做別的事;但是右邊的就只能把她 cout出來,相對地它的變化性就會比較少。

就像是這樣,就可以讓原本只能比較兩個值的函式,可以比較三個數字。

所以說,寫的越簡單函式,越有機會被使用的越多次(簡單就是美)。

在寫程式的時候,要盡量減少函式 coupling 的情況,盡可能 decouple 函式

命名

函式名稱、參數名稱、comment

也是盡量取清楚明瞭的名稱

comment 也要寫清楚,通常可以看 comment 就把函式的功能搞懂(意旨不需要看 definition)

Return value

在 void 裡面,雖然不需要回傳一個值給電腦,但是還是會有需要回傳的時刻

example:

  • given an input integer, write a program that prints out its digits, from the least significant to the most significant. (123 -> 321)
  • print out nothing if the input number is negative.
#include<iostream>
using namespace std;

void reversePrint(int);
int main()
{
	int i = 0;
	cin >> i;
	reversePrint(i);
	return 0;
}
void reversePrint(int i)
{
		if (i >= 0)
	{
		while (i > 0)
		{
			cout << i % 10;
			i /= 10;
		}
	}
	
}

或是可以寫成

#include<iostream>
using namespace std;

void reversePrint(int);
int main()
{
	int i = 0;
	cin >> i;
	reversePrint(i);
	return 0;
}
void reversePrint(int i)
{
		if (i < 0)
			return;
		while (i > 0)
		{
			cout << i % 10;
			i /= 10;
		}
		return;
}

用了 return; 會讓程式會比較好理解

因為 return 會有一點罷工,我不做了,的感覺,所以會在語意上比較好理解。

(improve readability and highlight parts)

operators also return values

operators 其實就是一個 function

Ex: 加法就是 : 給兩個 operands 回傳 num1 + num2

Ex: cin >> return 的值是 istream& (input stream + &) & 的概念未來可會提到。

例子:

int main()
{
	int sum = 0;
	int i = 0;

	cin >> i;
	while (i >= 0)
	{
		sum += i;
		cin >> i;
	}
	cout << sum;

	return 0;
}

或是可以用電腦裡面的 cmd 找到這個程式

然後先把輸入的檔案打在一個 txt 裡面(我打的是 1 5 6 0 8 9 -2)

然後用 < 這個符號,把他丟到執行檔裡面

然後我們把檔案改成這樣

int main()
{
	int sum = 0;
	int i = 0;

	cin >> i;
	while (cin >> i)// 這個時候 input stream 回傳一個值就會被evaluated 
	{              	//所以當沒有讀到東西的時候,就會被判定成 false
		sum += i;
	}
	cout << sum;

	return 0;
}

但要注意的是,如果是用鍵盤一直輸入,就沒辦法判定成 false ,需要用 txt檔裡面輸入才會判定。

EX:

如果把 n 個整數放在一個 txt 中,然後用程式把它印出來。

就可以這樣子寫:

int main()
{
	int sum = 0;
	int i = 0;
	
	while(cin >> i)
	{
		sum += i;
	}
	cout << sum;
	return 0;
}

當while(cin >> i) 的時候, input stream 會回傳一個值,這個值會被 evaluated,
因此當沒有讀到東西的時候,就會被判定成 false。

所以可以知道 cin 其實在背後作用的時候,是會回傳一個值給電腦的。

心得

韓式烤肉說真的我沒吃過

不過韓式拌飯真的很好吃

但是咖哩拌飯才是精隨。


上一篇
Day 12 - 陣列 b
下一篇
Day 14 - 函式拌飯
系列文
三十天內用C++寫出一個小遊戲30

尚未有邦友留言

立即登入留言