C語言自學攻略-函式

更新於 發佈於 閱讀時間約 12 分鐘

函式

將特定功能或常用的程式碼獨立成一個程式模組,稱為函式。

函式的優點為:

  1. 可重複使用。
  2. 可簡化程式複雜度,提升可讀性。
  3. 易於除錯與維護。

函式分為兩種:公用函式以及自訂函式。

公用函式

常見的標頭檔如下,只要在程式中引入(#include<標頭檔>),即可呼叫公用函式:

  1. <math.h>
  2. <time.h>
  3. <stdlib.h>

常見的數值類公用函式如下表:

raw-image
  • 備註:使用三角函數時,角度需轉為弧度,公式如下:

角度A → 弧度:A×π/180

時間、日期類函式如下表:

raw-image

使用範例:

#include <stdio.h>
#include <time.h>

int main() {
time_t t = time(&t);
printf("現在時間:%s\n", ctime(&t));

int j;
printf("執行加法運算5億次需要");
clock_t st =clock();
for(int i=0; i<500000000; i++)
{
j+=1;
}
clock_t et =clock();
printf("%.3lf秒",(double)(et-st)/CLOCKS_PER_SEC);

return 0;
}
  • 說明:
    • 迴圈前使用 clock() 函式獲取程式開始執行的時間(st)。
    • 迴圈後使用 clock() 函式獲取程式結束執行的時間(et)。
    • 將開始的時間與結束的時間相減除以CLOCKS_PER_SEC(代表CPU時鐘的每秒執行次數),即可得到所需的秒數。
    • 另外,由於参與計算的數值都是整數,所以須以(double)先強制轉換資料型態。

亂數函式如下:

raw-image

使用範例:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main() {
srand(time(NULL)); // 設定亂數種子,如果沒有設定,會造成下一次程式執行的輸出結果與前一次相同
for (int i = 0; i < 5; i++) {
printf("亂數%d: %d\n", i + 1, rand() % 100); // 產生 0-99 的亂數
}
for (int i = 0; i < 5; i++) {
printf("亂數%d: %d\n", i + 1, rand() % 100 + 1); // 產生 1-100 的亂數
}
return 0;
}

自訂函式

自訂函式是由開發者自己定義的函式,用於執行特定需求。它可以提升程式的可讀性、模組化和重複使用性。

函式定義:

返回值型別 函式名稱(參數型別 參數名稱, ...) {
// 函式內部的程式碼
return 返回值; // (如果函式需要回傳值)
}

若不需要傳入參數以及回傳變數值,則函式宣告如下:

void 函式名稱(參數型別 參數名稱, ...) {
// 函式內部的程式碼
}

簡單的自訂函式例子:

#include <stdio.h>

// 函式宣告
int add(int a, int b);

int main() {
int x = 5, y = 10;
// 呼叫函式
int result = add(x, y); //result用來接收x+y的結果
printf("兩數的總和為:%d\n", result);
return 0;
}

// 函式定義
int add(int a, int b) {
return a + b; // 傳回兩數的和,傳回int型別
}

當然,你也可以宣告後直接定義:

#include <stdio.h>

// 函式宣告並定義
int add(int a, int b){
return a + b; // 傳回兩數的和
}

int main() {
int x = 5, y = 10;
// 呼叫函式
int result = add(x, y);
printf("兩數的總和為:%d\n", result);
return 0;
}

請注意,當我們呼叫函式並傳入數值時,函式接收的是變數值的副本,而不是原變數本身。這種方式不會影響原始變數的內容。以下為簡單示範:

#include <stdio.h>

// 函式宣告
void modifyValue(int a);

int main() {
int a = 10;
printf("呼叫函式前,a = %d\n", a);

// 呼叫函式,傳遞 x 的值
modifyValue(a);

printf("呼叫函式後,a = %d\n", a);
return 0;
}

// 函式定義
void modifyValue(int a) {
a = 20; // 修改參數的副本
printf("函式內,a = %d\n", a);
}

從上面的程式碼,我們可以學到,函式中的a是你傳入數值的一個副本(傳入的數值複製給函式中的a變數),並且這個副本變數允許和主程式中的變數a同名,不過他們本質上並不一樣,所以修改函式中的a並不會影響主程式中的變數a

接下來我想要講解變數的生命週期:

變數的生命週期

#include <stdio.h>

// 全域變數
int globalVar = 100; // 生命週期:程式開始 → 程式結束

void testFunction() {
// 區域變數
int localVar = 10; // 生命週期:進入函式 → 函式結束
printf("函式內區域變數 localVar = %d\n", localVar);

// 靜態區域變數
static int staticVar = 0; // 生命週期:第一次進入函式 → 程式結束
staticVar++;
printf("函式內靜態區域變數 staticVar = %d\n", staticVar);
}

int main() {
// main 函式內的區域變數
int mainVar = 50; // 生命週期:進入 main() → main() 結束
printf("main 函式內區域變數 mainVar = %d\n", mainVar);

// 迴圈內的區域變數
for (int i = 0; i < 3; i++) {
int loopVar = i * 10; // 生命週期:每次進入迴圈 → 該次迴圈結束
printf("迴圈內區域變數 loopVar = %d\n", loopVar);
}

// 呼叫函式多次
testFunction(); // 第一次呼叫
testFunction(); // 第二次呼叫

// 使用全域變數
printf("全域變數 globalVar = %d\n", globalVar);

return 0;
}

變數生命週期與範圍解釋:

  1. 全域變數 (globalVar)
    • 生命週期:從程式啟動到結束。
    • 作用範圍:程式中的所有函式。
  2. main 函式內的區域變數 (mainVar)
    • 生命週期:進入 main() 時分配記憶體,退出 main() 時釋放。
    • 作用範圍:僅限於 main()
  3. 函式內的區域變數 (localVar)
    • 生命週期:每次進入函式時分配記憶體,函式結束時釋放。
    • 作用範圍:僅限於函式內。
  4. 靜態區域變數 (staticVar)
    • 生命週期:程式執行期間,且僅初始化一次,直到程式結束後釋放。
    • 作用範圍:僅限於該函式內,但值在函式多次呼叫間保留。
  5. 迴圈內的區域變數 (loopVar)
    • 生命週期:每次進入迴圈時分配記憶體,該次迴圈結束後釋放。
    • 作用範圍:僅限於迴圈內。

讀者目前應該瞭解了上述的概念。

前面有提到,單純傳數值進去(傳值),並不會影響原本的數值,哪有沒有甚麼方法是能夠直接修改到原本傳進來的變數呢?

這個方法叫做"傳址函式",不傳數值而改成傳入變數的位址,如此,在函式內就能直接對傳入的變數進行存取與修改。

下面我們示範一個數值交換函式:

#include <stdio.h>

// 函式宣告
void swap(int *a, int *b);

int main() {
int x = 5, y = 10;

printf("交換前:x = %d, y = %d\n", x, y);

// 傳址呼叫
swap(&x, &y);

printf("交換後:x = %d, y = %d\n", x, y);

return 0;
}

// 函式定義
void swap(int *a, int *b) {
int temp = *a; // 使用指標解參考,取得 a 指向的值
*a = *b; // 修改 a 指向的值
*b = temp; // 修改 b 指向的值
}

如此,就達到了直接修改傳入變數內容的目的了。(關於指標的觀念可以去觀看指標的那一章節)。


好,接著我必須再介紹一個不得不知道的函式觀念:遞迴。

遞迴

遞迴是甚麼呢? 遞迴是函式在執行過程中呼叫函式本身的一種技術。遞迴可以用來解決問題,特別是那些可以分解成較小規模的同類型問題的情況。 使用遞迴有兩個條件:

  • 結束條件
    • 遞迴需要有停止條件,用來避免無限遞迴。
    • 當滿足結束條件時,函式將不再呼叫自身,直接返回一個結果。
  • 遞迴條件
    • 將問題簡化並呼叫自身解決問題。
    • 通常將問題拆解成較小的子問題,直到達到結束條件。
返回值型別 函式名稱(參數) {
if (結束條件) {
return 結果; // 遞迴結束條件
} else {
遞迴呼叫; // 繼續呼叫自身
}
}

簡單觀念如下:

今天我們想要計算階乘,例如5!等於5X4X3X2X1,我們可以有以下的想法:

factorial(5) = 5 * factorial(4)
factorial(4) = 4 * factorial(3) //上面的factorial(4) = 4 * factorial(3),接著以此類推
factorial(3) = 3 * factorial(2)
factorial(2) = 2 * factorial(1)
factorial(1) = 1 (結束條件)
  • 可以注意到我們把問題一一分解成較小規模的同類型問題了。

最後我們依序把值帶回,求出數值

factorial(2) = 2 * 1 = 2
factorial(3) = 3 * 2 = 6
factorial(4) = 4 * 6 = 24
factorial(5) = 5 * 24 = 120 //最後得到答案的步驟
  • 所以最後數值就是5X(4X(3X(2X(1)))) = 1X2X3X4X5 = 120

程式範例:

#include <stdio.h>

// 遞迴函式定義
int factorial(int n) {
if (n == 0 || n == 1) {
return 1; // 結束條件:也要考慮0!得情況 : 0! = 1! = 1
} else {
return n * factorial(n - 1); // 繼續遞迴:n! = n * factorial(n-1)!
}
}

int main() {
int num = 5;
printf("%d 的階乘是:%d\n", num, factorial(num)); // 呼叫遞迴函式
return 0;
}
在當今數位時代,電資領域人才需求爆發式成長,不論是前端網頁設計、嵌入式開發、人工智慧、物聯網還是軟硬體整合,這些技術都在改變世界。而掌握 C/C++、Python、數位邏輯、電路學與嵌入式開發等大學電資領域的課程,正是進入這個高薪、高需求產業的關鍵!
留言
avatar-img
留言分享你的想法!

































































本章將介紹 C 語言的陣列 (Arrays),這是一種 連續儲存多個相同類型變數 的數據結構。透過陣列,我們可以有效管理與操作大量數據,並應用在 數據處理、排序、搜尋與多維數據存取 等情境中。
本章將介紹 C 語言的條件控制與迴圈控制,這是讓程式具備 邏輯判斷能力與重複執行能力 的關鍵技術。透過 if 判斷式、switch 多重選擇、for 迴圈、while 迴圈 等控制結構,我們可以有效管理程式流程,提升代碼的 效率與可讀性。
本章將介紹 C 語言的運算子 (Operators),這是程式語言的基礎,負責執行數值計算、條件判斷與邏輯運算。我們將最先學習變數在記憶體中的樣子,這是非常重要的觀念,接著漸入到算術運算、關係運算、邏輯運算、位元運算與三元運算子等,並透過 運算子優先順序 來確保正確的運算執行順序。
本文章介紹了 C 語言putchar, getchar, puts, fgets函數及其使用方法與常見問題解決方案。包含程式碼範例、問題分析及解決方法,幫助讀者理解並避免輸入錯誤。
在C語言中,scanf()可能並沒有我們所想的那麼簡單且單調,本章節會列出4點補充的使用方式。這些都是容易忽視的小知識。
本章將介紹 C 語言的輸入與輸出 ,透過本章系統性的學習與使用示範,你將能夠靈活掌握 C 語言的資料讀取與輸出技巧。
本章將介紹 C 語言的陣列 (Arrays),這是一種 連續儲存多個相同類型變數 的數據結構。透過陣列,我們可以有效管理與操作大量數據,並應用在 數據處理、排序、搜尋與多維數據存取 等情境中。
本章將介紹 C 語言的條件控制與迴圈控制,這是讓程式具備 邏輯判斷能力與重複執行能力 的關鍵技術。透過 if 判斷式、switch 多重選擇、for 迴圈、while 迴圈 等控制結構,我們可以有效管理程式流程,提升代碼的 效率與可讀性。
本章將介紹 C 語言的運算子 (Operators),這是程式語言的基礎,負責執行數值計算、條件判斷與邏輯運算。我們將最先學習變數在記憶體中的樣子,這是非常重要的觀念,接著漸入到算術運算、關係運算、邏輯運算、位元運算與三元運算子等,並透過 運算子優先順序 來確保正確的運算執行順序。
本文章介紹了 C 語言putchar, getchar, puts, fgets函數及其使用方法與常見問題解決方案。包含程式碼範例、問題分析及解決方法,幫助讀者理解並避免輸入錯誤。
在C語言中,scanf()可能並沒有我們所想的那麼簡單且單調,本章節會列出4點補充的使用方式。這些都是容易忽視的小知識。
本章將介紹 C 語言的輸入與輸出 ,透過本章系統性的學習與使用示範,你將能夠靈活掌握 C 語言的資料讀取與輸出技巧。
你可能也想看
Google News 追蹤
Thumbnail
這篇內容,將會講解什麼是函式,以及與函式相關的知識。包括函式的簡介、Runtime Function、自訂函式、Script Function 腳本函式、Method 方法。
主要來講宣告函式跟箭頭函式 : 宣告函式(Function Declaration) 語法: function functionName(parameters) { return result; } 特點: 使用 function 關鍵字 函式名稱是必需的 存在函式
Thumbnail
在這一章中,我們探討了 PHP 中的函數,包括函數的基本結構、不同的函數定義方式(如函數聲明、函數表達式、箭頭函數和匿名函數)以及如何呼叫函數。我們還討論了函數的參數處理方式,包括單個參數、多個參數、預設參數值和剩餘參數。此外,我們還介紹了函數的返回值,包括返回單個值、返回物件和返回函數的情況。
Thumbnail
本章節旨在介紹TypeScript中的函數,包括其基本結構、如何呼叫函數、函數的參數以及函數的返回值等相關概念。通過本章節,讀者可以學習到如何在TypeScript中使用不同的方式來定義函數,如函數聲明、函數表達式、箭頭函數和匿名函數等。
Thumbnail
本章節旨在介紹 C# 中函數的基本結構,包括訪問修飾符、返回類型、方法名稱、參數列表和方法體。同時,也介紹了函數的各種呼叫方式、參數傳遞方式和返回值類型。讀者可以通過本章節,深入理解 C# 中函數的使用和應用。
※ 函式基礎介紹: ※ JavaScript 特殊的函式特性: 函式可以當成值來傳遞 (可以放進變數或放進物件) 函式可以當成函式的參數 callback - 在特定事件中觸發函式 (非同步特性) ※ 函式的基本寫法: ※ 調用 (invoke) 函式: "調用" 意指呼叫或執行
Thumbnail
今天來介紹python的函式 函式在python中是非常重要的一環,因為到了後期,程式會越來越複雜。 而函式可以想成是容易管理的小程式,當我們需要使用時,只需呼叫即可。
對於程序式編程來說,程式是由一系列的指令組成,例如計算數值、印出訊息、修改變數、呼叫子程序、配置變數的記憶體空間等。定義函式是為了讓一些程序可以重複利用,因此稱為子程序,其中參數為子程序中特別的變數,讓我們能夠透過它們控制子程序的行為。函式的回傳值只是一種方便將結果帶回來的方法,但一般只能回傳一個值
Thumbnail
本文將介紹自定函式及應用,利用程式範例解釋為什麼要用到自定函式 自定函式好處當然就是,讓你的程式碼看起來比較簡潔,在重複使用到的程式碼區塊,可以包裝成函式,讓你重複使用它。
Thumbnail
介紹C++ 語法 資料型態,架構說明 程式語言為人類與電腦溝通的工具 程式設計流程: 定義問題 -> 問題分析 -> 撰寫演算法 ->程式撰寫 -> 程式執行及維護
Thumbnail
這篇內容,將會講解什麼是函式,以及與函式相關的知識。包括函式的簡介、Runtime Function、自訂函式、Script Function 腳本函式、Method 方法。
主要來講宣告函式跟箭頭函式 : 宣告函式(Function Declaration) 語法: function functionName(parameters) { return result; } 特點: 使用 function 關鍵字 函式名稱是必需的 存在函式
Thumbnail
在這一章中,我們探討了 PHP 中的函數,包括函數的基本結構、不同的函數定義方式(如函數聲明、函數表達式、箭頭函數和匿名函數)以及如何呼叫函數。我們還討論了函數的參數處理方式,包括單個參數、多個參數、預設參數值和剩餘參數。此外,我們還介紹了函數的返回值,包括返回單個值、返回物件和返回函數的情況。
Thumbnail
本章節旨在介紹TypeScript中的函數,包括其基本結構、如何呼叫函數、函數的參數以及函數的返回值等相關概念。通過本章節,讀者可以學習到如何在TypeScript中使用不同的方式來定義函數,如函數聲明、函數表達式、箭頭函數和匿名函數等。
Thumbnail
本章節旨在介紹 C# 中函數的基本結構,包括訪問修飾符、返回類型、方法名稱、參數列表和方法體。同時,也介紹了函數的各種呼叫方式、參數傳遞方式和返回值類型。讀者可以通過本章節,深入理解 C# 中函數的使用和應用。
※ 函式基礎介紹: ※ JavaScript 特殊的函式特性: 函式可以當成值來傳遞 (可以放進變數或放進物件) 函式可以當成函式的參數 callback - 在特定事件中觸發函式 (非同步特性) ※ 函式的基本寫法: ※ 調用 (invoke) 函式: "調用" 意指呼叫或執行
Thumbnail
今天來介紹python的函式 函式在python中是非常重要的一環,因為到了後期,程式會越來越複雜。 而函式可以想成是容易管理的小程式,當我們需要使用時,只需呼叫即可。
對於程序式編程來說,程式是由一系列的指令組成,例如計算數值、印出訊息、修改變數、呼叫子程序、配置變數的記憶體空間等。定義函式是為了讓一些程序可以重複利用,因此稱為子程序,其中參數為子程序中特別的變數,讓我們能夠透過它們控制子程序的行為。函式的回傳值只是一種方便將結果帶回來的方法,但一般只能回傳一個值
Thumbnail
本文將介紹自定函式及應用,利用程式範例解釋為什麼要用到自定函式 自定函式好處當然就是,讓你的程式碼看起來比較簡潔,在重複使用到的程式碼區塊,可以包裝成函式,讓你重複使用它。
Thumbnail
介紹C++ 語法 資料型態,架構說明 程式語言為人類與電腦溝通的工具 程式設計流程: 定義問題 -> 問題分析 -> 撰寫演算法 ->程式撰寫 -> 程式執行及維護