沙耶
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    1
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # 自定義函數 function 函數將一些程式碼包成一個個子任務,每次需要時直接呼叫即可。 除了有助整理邏輯,適當地包裝重覆的程式碼,也能有效降低修改時的風險。 例如將計算總和包裝成 calc_sum() 後,求平均的程式碼會變成這樣: ```cpp= double avg = calc_sum(ary, n) * 1.0 / n; ``` 而求兩個陣列平均誰大誰小,則可簡化成: ```cpp= if (calc_sum(ary0, n0) < calc_sum(ary1, n1)) { // ... } ``` 相對於寫下求總和的迴圈,呼叫函數可以從命名更容易理解它的用意, 且在其他地方需要計算總和時,可以不用再寫同樣的程式碼。 萬一寫錯,也只需修改函數內的程式碼,無需同時修改每個求平均的地方。 ## 宣告 declaration :::info 宣告函數分成四個部份:函數型別、名字、參數、以及本體。 ::: 例如宣告一個函數 `f(x) = 2x - 1`,則分析一下它的四個部份: - 名字:`f`,有名字才知道是在叫誰 - 參數:一個整數 `x`,決定呼叫時需要提供的資訊 - 型別:整數 `int`,決定函數執行結果的型別 - 本體:計算 `2x - 1` 用的,由大括號包起的一段程式碼 ```cpp= // 結果型別 名字(參數列表) // { // 本體 // } int f(int x) { int res = x*2 - 1; return res; } ``` 以上程式碼宣告一個名為 f 的函數,要求一個整數參數 x, 計算出整數結果 `2x - 1` 並回報。 ### 函數的宣告位置 由於 main() 也是個自定義函數,和其它自定義函數應是對等關係, 因此必須宣告在 main() 之外; 又,和變數一樣,函數也必須在使用前宣告,因此通常宣告於 main() 之上。 例如以下是一個輸入 x 輸出 f(x) 的範例: ```cpp= #include <iostream> using namespace std; int f(int x) { int res = x*2 - 1; return res; } int main() { int x, y; cin >> x; y = f(x); cout << y << '\n'; return 0; } ``` 有興趣可以試試將 f() 的宣告放在 main() 之下,看看會發生什麼事。 ### 僅宣稱函數的存在 如果真的非常想將函數宣告於 main() 下方,或者有函數互相呼叫等需求, 可先宣稱「有這樣子的函數存在」但略過本體不寫。 最終還是必須補上本體,且必須與宣告的樣子一致。 ```cpp= #include <iostream> using namespace std; int main() { int x, y; // ↓↓↓↓ 先宣稱「有這樣子的函數存在」但略過本體 ↓↓↓↓ int f(int); // ↑↑↑↑ 先宣稱「有這樣子的函數存在」但略過本體 ↑↑↑↑ cin >> x; y = f(x); cout << y << '\n'; return 0; } // 宣告在全域的 f() 本體 int f(int x) { int res = x*2 - 1; return res; } ``` 無本體時,宣告在全域或區域皆可,只有本體的宣告必須在全域。 無本體時參數的名字可以忽略,只須寫下型別。 有興趣可以試試宣稱存在的函數與實際本體不符合時,會發生什麼事。 ## 函數呼叫 function call 呼叫函數的名字,加上小括號 () 傳遞必要的參數後, 就能執行該函數,並取得函數回報的執行結果。 ```cpp= f(5); ``` 函數呼叫本身在 C++ 中,代表一個運算元, 其值為回報的結果,型別為函數型別。 按上述的宣告,`f(5)` 代表著整數 9。 由於是運算元,可以參與運算式。 ```cpp= // 2x10 - 1 int y = f(10); // 5 * (2x10 - 1) + (2x9 - 1) int y2 = 5 * f(10) + f(9); cout << y << ' ' << y2 << '\n'; ``` ### 執行流程的變化 程式的執行是有順序的,每行程式碼都仰賴於它上一行程式碼執行完畢的結果。 因此,每行程式碼需等待它上一行程式碼執行完畢。 函數呼叫本身代表著函數所回報的計算結果, 因此,當運算式需要知道它所代表的值,才能繼續時, 整個流程就會暫停下來,先執行函數呼叫,等執行完回報結果,才會繼續進行。 ```cpp= // 這行在賦值前必須算出 f(5) 才知道賦值的內容,因此必須等待 f(5) 執行完畢 int x = f(5); // 這行仰賴上一行執行完的狀況,因此必須等待上一行執行完畢 int y = x * 2; ``` :::warning 運算式不見得需要知道所有的值,才能繼續進行下去。 因此,在運算式不需要知道函數呼叫的值時,函數是不會被呼叫的。 ::: 以下是個有被寫進運算式,但因為不需要知道它的值,實際沒被呼叫的例子: ```cpp= int g(int t) { cout << "g(" << t << ")\n"; return t; } ``` 這樣可以透過輸出判斷是否有被呼叫,而 main() 則準備有寫進去、 但實際可能不需要被計算,因此沒被呼叫的程式碼: ```cpp= int q; cin >> q; if (q && g(8)) { cout << "executed!!\n"; } ``` 在輸入為 0 時,由於 && 已經確定不成立,因此不需要知道 g(8) 的值; 輸入非 0 時,則仰賴 g(8) 的值,因此會被呼叫。 ## 參數 parameter 宣告時,小括號中可指定任意數量的參數,呼叫時必須依照要求全部提供。 宣告參數時需指定型別和名稱,像一般的變數宣告一樣。 ```cpp= int max(int p, int q) { if (p > q) { return p; } return q; } ``` 上述的程式碼要求兩個整數參數,回傳較大的那一個。 呼叫時傳遞的參數,會被依順序**複製**到對應的變數中。 ```cpp= int t = max(16*9, 18*8); ``` 上述程式碼會先將 $16 \times 9$ 的結果複製一份放在變數 p, 將 $18 \times 8$ 的結果複製一份放在變數 q, 再開始執行函數的本體。 :::warning 實際上 C++ 在參數上存在更多的細節, 例如傳值傳址傳參考、重載、參數預設值、可省略參數、可變數量參數…等, 由於大多與競賽並不是那麼相關,在此僅列出一些關鍵字, 有興趣者可自行查閱相關資料。 ::: ### 參數的複製 由於參數是複製一份,因此在函數內進行的修改,並不會影響原本的變數。 ```cpp= int twice(int x) { x *= 2; return x; } ``` 看似會將參數變成兩倍,實際上只對 twice() 抄寫的那一份 x 做出變更。 ```cpp= int x = 5; twice(x); cout << x << '\n'; ``` 在執行後,x 的值一樣是 5。 只有 twice 抄的那份會被變更,原本的不會。 也因為如此,我們才能傳遞一些不能被變更的東西作為參數。 試想,如果傳入的東西是有可能會被變更的,那以下程式碼會發生什麼事? ```cpp= twice(5); twice(2+3*6); ``` 顯然常數 `5` 和運算式 `2+3*6` 都是不能被更動、賦值的東西。 ### 當參數型別為陣列時 宣告時同樣加中括號,表示它是個陣列;但不需註明長度。 若有加註長度,會被省略不看。 ```cpp= double calc_avg(int ary[], int n) { int sum, i; for (i=0, sum=0; i<n; i++) { sum += ary[i]; } return (double)sum / n; } ``` 以上是其中一個參數為陣列的例子。 ```cpp= int ary[16], n, i; cin >> n; for (i=0; i<n; i++) { cin >> ary[i]; } double avg = calc_avg(ary, n); cout << avg << '\n'; ``` :::info 值得注意的是:參數為陣列時,是把陣列所存放的位置,抄寫一份傳遞進去, 因此修改陣列裡存放的內容時,是會修改到原本陣列的。 ::: :::warning 或許有些範例會以 `int *ary` 的方式來宣告參數, 可達成的效果基本上是相同的,只是在意義上容易被解讀成其它意思。 ::: ### 當參數型別為多維陣列時 由於多維陣列在位址計算上,依賴於第一維以外每一維的大小, 因此除了必須加註,也必須保持一致才行。 ```cpp= int get_sum(int (*matrix)[4], int n) { int i, j, sum; for (i=0; i<n; i++) { for (j=0; j<4; j++) { sum += matrix[i][j]; } } return sum; } ``` 使用 `int (*matrix)[4]` 宣告一個陣列, 其每一個 element 是一個「長度 4 的一維 int 陣列」。 ```cpp= int a[8][4], b[4][8]; // ok cout << get_sum(a, 8) << '\n'; // compile error cout << get_sum(b, 4) << '\n'; ``` 這是因為 b 的每個 element 是一個「長度 8 的一維 int 陣列」, 並不是「長度 4 的一維 int 陣列」,型別不符。 就像要求 string 型別的參數,呼叫時卻傳入 int 是類似的感覺。 明明要的是食物,卻被塞一些不能吃的東西。 ## 回傳值 return value 函數的本體可透過 `return` 來回傳一個值作為計算結果, 被回傳的值其型別必須與函數型別一致。 一旦執行到 `return` 函數便會停止執行。 ```cpp= int divide(int p, int q) { if (q == 0) { cout << "NOOOOO you CANNOT divide 0!!\n"; return 0; cout << "after return 0, this won't be executed.\n"; } return p / q; } ``` 例如上述程式碼,在 q == 0 時便會因 `return 0;` 而結束執行, 因此不會執行到 `p / q` 這個會導致除以 0 的地方。 如果不夠明顯,可以看第 7 行的 cout 是否有被執行。 ## void 型別的函數 如果這函數僅用來執行某些程式碼,不須回報任何結果, 可將型別宣告為 void。 它將不再能回傳任何值,也不能作為運算元參與計算。 仍然可以使用 return 結束函數執行,但不能回傳任何值。 ```cpp= void output(int t) { if (t < 0) { cout << "negative.\n"; // return 仍會結束執行,但不得傳回任何值,必須接著分號 ; return; } cout << "non-negative.\n"; } ``` 上述程式碼宣告一個型別為 void 的函數, 將只能執行,不會回報任何值,無法參與計算。 ```cpp= // compile error int a = output(-4); // 僅能呼叫不能參與計算 output(-4); ``` ## 歡樂練習時間? 由於難以找到非使用函數不可的題目, 且使用函數較不使用函數明顯有利的情況,多半是程式足夠大而繁複的時候, 因此沒有練習題。 若想練習,可以試試完成以下幾個函數並自行撰寫 main() 測試: ```cpp= int get_abs(int t) { // 回傳 t 的絕對值 } ``` ```cpp= int is_prime(int n) { // 回傳 0 代表 n 不是質數;回傳 0 以外的整數代表 n 是質數 } ``` ```cpp= int get_gcd(int p, int q) { // 回傳 p, q 的最大公因數 } ``` ```cpp= int get_max(int ary[], int st, int ed) { // 回傳陣列 ary 中,範圍 [st, ed] 間最大的元素 } ``` ```cpp= int max3(int p, int q, int r) { // 回傳 p, q, r 中最大的整數 } ``` ```cpp= int str_cmp(string p, string q) { // 比較字串 p, q 的字典序,回傳負數代表 p 字典序比 q 小; // 回傳正數代表 p 字典序比 q 大;其它情況一律回傳 0 } ``` ```cpp= char case_change(char c) { // 如果 c 是大寫,回傳它的小寫; // 如果 c 是小寫,回傳它的大寫; // 如果都不是,回傳 c 本身 } ``` ```cpp= const int DIGIT = 0; const int UPPER = 1; const int LOWER = 2; const int OTHER = 3; string pickup(string s, int pick_type, bool trans) { // 從 s 取出想要的文字,按照原順序組成字串傳回 // pick_type 只會有上面定義的四種可能 // trans 表示在 UPPER 或 LOWER 時,不符合的字母要不要變換後加入 // 例如 UPPER 時,trans 如果是 true 表示小寫字母也要取,且轉成大寫 // trans 不影響字母以外的文字 } // 以下是呼叫例 string t = "3A7k5a g6I4!"; cout << pickup(t, DIGIT, false) << '\n'; // "37564" cout << pickup(t, OTHER, true) << '\n'; // " !" cout << pickup(t, LOWER, false) << '\n'; // "kag" cout << pickup(t, UPPER, true) << '\n'; // "AKAGI" ``` {%hackmd @sa072686/__style %} ###### tags: `競程:初章`, `競程`

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully