-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathch08.html
22 lines (22 loc) · 12.3 KB
/
ch08.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html><html></html><head><meta charset="UTF-8"><meta content="text/html; charset=UTF-8" http-equiv="content-type"><link href="style.css" rel="stylesheet" type="text/css"><link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"><script src="jquery/dist/jquery.min.js"></script><script type="text/javascript" src="./selectchapter.js"></script><script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script><title>第八章 自定義函數與資料型別</title></head><body><nav class="navbar navbar-default" role="navigation"><div class="container-fluid"><div class="navbar-header"><a class="navbar-brand" href="index.html">板中資訊社</a></div><div><ul class="nav navbar-nav"><li class="active"><a href="#">C++</a></li><li class="dropdown"><a class="dropdown-toggle" href="#" data-toggle="dropdown">課程<b class="caret"></b></a><ul class="dropdown-menu"><li><a href="ch01.html">第一章 立刻動手</a></li><li><a href="ch02.html">第二章 變數與指定運算子「=」</a></li><li><a href="ch03.html">第三章 比較運算子與 if 陳述式</a></li><li><a href="ch04.html">第四章 迴圈</a></li><li><a href="ch05.html">第五章 基礎資料型別</a></li><li><a href="ch06.html">第六章 字元與字串</a></li><li><a href="ch07.html">第七章 陣列</a></li><li><a href="ch08.html">第八章 自定義函數與資料型別</a></li><li><a href="ch09.html">第九章 排序</a></li></ul></li><li class="dropdown"><a class="dropdown-toggle" href="#" data-toggle="dropdown">附錄<b class="caret"></b></a><ul class="dropdown-menu"><li><a href="basic_type.html">A 基礎資料型別</a></li></ul></li></ul></div></div></nav><h1>第八章 自定義函數與資料型別</h1><button id="button1">使用者自定義函數</button><button id="button2">#define</button><button id="button3">自定義資料型別</button><div class="para" id="para1" style="display:none;"><h2>8.1 使用者自定義函數</h2><li><a href="http://contest.cc.ntu.edu.tw/npsc2007/doc/2007junfinal.doc">2007 NPSC 國中組決賽 B. 友好數</a></li><p>n 的真因數:除了 n 本身以外的所有因數,包含 1。友好數:如果 n 真因數和為 m,m 的真因數和為 n,則 n、m 互為「友好數」。題目:給定 n,求 n 的友好數。若 n 的友好數為 n 本身,請輸出「=n」,若 n 沒有友好數,請輸出「0」。</p><p>這題可以用以下的程式碼來 AC。</p><script src="https://gist.github.com/allem40306/02d0372881daf3ae849bba528bc424f4.js?file=ch08-01.cpp"></script><p>從上面的程式中,我們先求 n 的真因數和 m,再求 m 的真因數和n1,求真因數和的動作做了兩次,相同的程式碼也寫了兩次。這樣的寫法除了浪費記憶體外,在軟體工程上也有它的問題,因為它會造成維護上的困擾。將來如果求真因數和的程式需要修改,那麼我們得修改兩處,萬一其中一處遺漏了,就會造成程式的錯誤。</p><p>因此,像這樣重覆使用的程式碼,應讓有一個機制讓它只寫一次就好,這個機制叫作「函數」。我們把上面的程式碼用「函數」改寫如下:</p><script src="https://gist.github.com/allem40306/02d0372881daf3ae849bba528bc424f4.js?file=ch08-02.cpp"></script><p>在這個程式裡,一共有兩個「函數」(funtcion):int main () 及 void sof ()。void所代表的意義我們待會再討論。int main ()
是程式的「入口」,程式執行時,會先執行這個「函數」。至於其他的函數,只有在被「呼叫」(call)時才會執行。如果你寫了一個函數卻不去呼叫它,那麼它就不會被執行,等於是白寫。因此,在 int main () 中有一個呼叫 sof ()
函數的陳述式:</p><script src="https://gist.github.com/allem40306/02d0372881daf3ae849bba528bc424f4.js?file=ch08-03.cpp"></script><p>執行到這行時,程式就會先跳到 void sof () 函數去,等 void sof () 裡的程式執行完後再跳回 int main ()。</p><p>不過,上面這個程式在編譯時得到以下的錯誤訊息:</p><p>1>d:\cpps\cpps\2007jfb. 友好數a.cpp(6) : error C2065: 'm' : 未宣告的識別項<br>1>d:\cpps\cpps\2007jfb. 友好數a.cpp(7) : error C2065: 'f' : 未宣告的識別項<br>1>d:\cpps\cpps\2007jfb. 友好數a.cpp(7) : error C2065: 'n' : 未宣告的識別項</p><p>在 int main () 的裡面我們定義了 4 個變數。</p><script src="https://gist.github.com/allem40306/02d0372881daf3ae849bba528bc424f4.js?file=ch08-04.cpp"></script><p>這種定義在函數內部的變數我們稱之為「區域變數」,它的有效範圍僅限於該函數的內部。所以這 4 個變數是 int main ()
自己的變數,void sof () 是存取不到的。因此當 void sof () 中使用到 n, m, f
等變數時,便會產生「未宣告的識別項」的錯誤。</p><p>你當然也可以在 void sof () 中自己定義這些變數:</p><script src="https://gist.github.com/allem40306/02d0372881daf3ae849bba528bc424f4.js?file=ch08-05.cpp"></script><p>這樣程式雖然通過編譯並執行,但是卻產生的下列的「警告」:</p><p>1>d:\cpps\cpps\2007jfb. 友好數a.cpp(8) : warning C4700: 使用了未初始化的區域變數 'n'<br>1>d:\cpps\cpps\2007jfb. 友好數a.cpp(19) : warning C4700: 使用了未初始化的區域變數
'm'</p><p>根據程式的邏輯,在 void sof () 所使用的 n 應該是在 int main () 所輸入的 n。我們另行在 void sof ()
所宣告的 n 卻是另一個 n,儘管兩個變數名稱都是 n,但是它們卻是不同的個體。你在 int main () 輸入了 n,但是 void
sof () 的 n 卻沒有改變。</p><p>要讓 int main () 和 void sof () 共用一個 n,你需要把它定義為「全域變數」,方法是把這個 n
宣告在兩個函數的「外面」:</p><script src="https://gist.github.com/allem40306/02d0372881daf3ae849bba528bc424f4.js?file=ch08-06.cpp"></script><p>記得要同時把函數內的同名區域變數拿掉,否則程式會優先取用區域變數,而不是全域變數。</p><p>由於 int main () 和 void sof () 都會用到 n,
m,所以這兩個全域變數的宣告要出現在這兩個函數之前,否則還是會出現「未宣告的識別項」的錯誤。同理,由於 int main () 中會去呼叫
sof (),所以 void sof() 函數也要出現在 int main () 之前。</p><p>你可能會好奇,既然 n, m 要宣告為全域變數,為什麼不把 n1 和 f
也一起宣告為全域,這樣程式也比較簡短。基於易於維護的因素,除非真正必要的時候,我們通常會儘量避免全域變數的使用。由於每個函數都可以去修改全域變數
的值,有時候甲函數修改了某變數的值,乙函數卻不知道,這就會造成一些錯誤了。在上面的程式中,int main () 輸入了 n 的值,而
void sof () 則需要求這個 n 的真因數和,void sof () 所求得的真因數和 m 也需要在 int main ()
中做進一步的判斷與處理,所以這兩個變數一定要宣告成全域變數,其他的變數我們就宣告為區域變數。在這個程式中,即使你把 n, m, n1, f
都宣告為全域變數,程式仍能跑出正確的結果,但是基於培養良好的程式設計習慣,我們還是把 n1 和 f 宣告為區域變數比較好。</p><p>經過這番調整之後,這個程式終於可以正確執行了。但是我們當初寫 void sof ()
這個函數的目的就是希望可以把相同的兩段程式碼簡化成一段,當我們試圖進一步用 void sof () 來求 m
的真因數和時,卻發現由於變數命名的關係, void sof () 只能用來求 n 的真因數和,沒有辦法用來求 m
的真因數和。為了解決這個問題,我們把 void sof () 所使用的變數名稱修改如下:</p><script src="https://gist.github.com/allem40306/02d0372881daf3ae849bba528bc424f4.js?file=ch08-07.cpp"></script><p>也就是說,我們用 p 來取代所有的 n、用 q 來取代所有的 m。然後我們在呼叫 void sof() 之前先把 n 代入 p,求出 p
的真因數和 q 之後,再把 q 代入 m:</p><script src="https://gist.github.com/allem40306/02d0372881daf3ae849bba528bc424f4.js?file=ch08-08.cpp"></script><p>雖然這樣麻煩一點,但是如此一來,我們就可以用同一個 void sof () 來求 m 的真因數和了:</p><script src="https://gist.github.com/allem40306/02d0372881daf3ae849bba528bc424f4.js?file=ch08-09.cpp"></script><p>完整程式碼如下:</p><script src="https://gist.github.com/allem40306/02d0372881daf3ae849bba528bc424f4.js?file=ch08-10.cpp"></script><li><a href="https://zerojudge.tw/ShowProblem?problemid=d225">d255. 11417 - GCD</a></li><p>這一題,它把題目的要求都寫成程式給你了,你只要複製題目中的程式,再加上變數的宣告、0 尾版的迴圈、及結果的輸出,答案就出來了。</p><script src="https://gist.github.com/allem40306/02d0372881daf3ae849bba528bc424f4.js?file=ch08-11.cpp"></script><p>但是再仔細看一下程式,其中用了一個 GCD 函數是 C++ 中沒有的。這時候你就得自己為它定義一個 GCD 函數來求最大公因數了。</p></div><div class="para" id="para2" style="display:none;"><h2>8.2 #define</h2><p>#define則可以自行定義常數</p> <p>如以下程式:</p><script src="https://gist.github.com/allem40306/02d0372881daf3ae849bba528bc424f4.js?file=ch08-12.cpp"></script><p>裡面的1000出現很多次,我們用#define簡化</p><script src="https://gist.github.com/allem40306/02d0372881daf3ae849bba528bc424f4.js?file=ch08-13.cpp"></script><p>用#define的好處不只是可以少打字,重要的是在修改時只要改變常數就好了,節省修改時間,亦不會漏改</p><p>也有人用 const int</p><script src="https://gist.github.com/allem40306/02d0372881daf3ae849bba528bc424f4.js?file=ch08-14.cpp"></script><p>#define 也可以誰一些簡單函數</p><script src="https://gist.github.com/allem40306/02d0372881daf3ae849bba528bc424f4.js?file=ch08-15.cpp"></script></div><div class="para" id="para3" style="display:none;"><h2>8.3 自定義資料型別</h2><p>假如今天給你A星的座標,給你其他星的座標,要你判斷之間距離,得出了以下變數</p><p>(1)A星的座標(x,y)(2)其他星的座標(x,y)</p><p>--> int ax, ay, ox[100], oy[100];</p><p>但今天你覺得不太雅觀或可讀性低,你可以自己定義一個結構</p><script src="https://gist.github.com/allem40306/02d0372881daf3ae849bba528bc424f4.js?file=ch08-16.cpp"></script><ol><li>star 自定義資料型別名稱</li> <li>int x,y; 自定義資料型別內的內容</li> <li>可以在}和;(如(a))之間命名一個變數,也可以如(b)一樣另外新增變數。<br><strong>(注意! }後的;不可刪除)</strong></li></ol><p>這樣程式可讀性變高了!!!</p><h3>struct&class的比較</h3><p>除了struct,class也可以用來當自定義資料型別,但它們有什麼不同?
其實只有一個,就是當它們未說明裡面的內容是 public(所有區域都可以用)、private(只有在此區域內才可被使用/更改)</p><p>struct內都是 public,class內都是private
要讓兩者相同,如下:</p><script src="https://gist.github.com/allem40306/02d0372881daf3ae849bba528bc424f4.js?file=ch08-17.cpp"></script><script src="https://gist.github.com/allem40306/02d0372881daf3ae849bba528bc424f4.js?file=ch08-18.cpp"></script><p>我們的變數通常為全域變數,所以接下來都用struct的呈現程式碼</p><p></p><h3>struct裡的函式</h3><p>在struct裡,我們也可以放入函式,如下</p><script src="https://gist.github.com/allem40306/02d0372881daf3ae849bba528bc424f4.js?file=ch08-19.cpp"></script><p>首先有一個函式和結構式同名,這個叫建構器,來建立一個相同的資料型別,再來是plus和minus,他會依據資料型別類的資料執行結果,如本題c裡的a=5,b=6,執行plus的11,執行minus的-1。struct還可以建立解構子、運算子等,考慮各位的理解度差異,會把詳細的用法放在附錄裡(待補)</p><p>struct的用途在於可以把資料一組組存起來,易存取,在排序時也可以一起移動,詳情請見下章</p><h3>應用(大數/浮點數)</h3><p>我們知道c++最大的整數為2^64-1,但有些題目所需求的數字比這個大,這時可以利用struct來解決</p><p>請參考<a href="http://www.csie.ntnu.edu.tw/~u91029/Number.html#4">演算法筆記:Big Number</a></p><p>記得浮點數誤差嗎,利用struct來提高精準度吧!</p><br><br></div></body>