一、引言
????????在 C 語言中,函數是一組執行特定任務的代碼塊。通過將復雜的程序邏輯劃分為多個函數,不僅能提高代碼的可讀性、可維護性,還便于代碼的復用。無論是簡單的數學計算,還是復雜的系統操作,函數都發揮著核心作用。掌握函數的使用方法,是提升 C 語言編程能力的重要環節。
二、函數的定義
? 2.1 基本語法:
返回值類型 函數名(參數列表) { ????// 函數體 ????語句; ????return 返回值; } |
返回值類型:指定函數執行完成后返回的數據類型,若函數無需返回值,使用void。
函數名:遵循標識符命名規則,用于唯一標識函數。
參數列表:可以包含零個或多個參數聲明,參數之間用逗號分隔,若沒有參數,使用void或留空。
函數體:由一系列語句組成,是函數執行的具體邏輯。
return 語句:用于終止函數執行,并將返回值傳遞給調用者。若無返回值,return語句可省略。
? 2.2 示例:
????????計算兩個整數之和的函數:
int add(int a, int b) {int sum = a + b;return sum;
}
????????此函數add接收兩個int類型參數a和b,計算它們的和并返回。
三、函數的聲明
? 3.1 聲明的作用:
????????函數聲明告知編譯器函數的名稱、返回值類型和參數類型,使編譯器在編譯時能夠對函數調用進行合法性檢查。函數聲明通常放在調用函數的代碼之前。
??3.2 語法:
返回值類型 函數名(參數列表); |
????????聲明與定義類似,但函數聲明末尾需加分號,且函數體部分省略。例如,上述add函數的聲明為:
int add(int a, int b);
? 3.3 聲明的位置:
????????全局聲明:在所有函數外部聲明,作用域為整個源文件,可被文件內所有函數調用。
????????局部聲明:在函數內部聲明,作用域僅限于該函數內部。一般用于在函數內部調用其他自定義函數時,確保編譯器知曉被調用函數的信息。
四、函數的調用
? 4.1 調用方式:
????????通過函數名后跟一對圓括號來調用函數,若函數有參數,在括號內傳入相應參數值。例如調用上述add函數:
int result = add(3, 5);
????????此語句將調用add函數,傳入參數 3 和 5,函數返回值賦給result變量。
??4.2 函數調用過程:
????????參數傳遞:將實際參數的值復制給函數定義中的形式參數。
????????執行函數體:按照函數體中的語句順序執行代碼。
????????返回值處理:遇到return語句時,函數終止執行,將返回值傳遞給調用處,繼續執行調用函數后的代碼。
五、函數參數
? 5.1 形式參數與實際參數:
????????形式參數:函數定義中參數列表里的參數,在函數被調用前并不占用實際內存空間,只有在函數調用時才被分配內存并接收實際參數的值。
????????實際參數:函數調用時傳遞給函數的表達式、變量或常量。例如在add(3, 5)中,3 和 5 就是實際參數。
??5.2 參數傳遞方式:
????????值傳遞:C 語言默認的參數傳遞方式。實際參數的值被復制到形式參數中,函數內部對形式參數的修改不會影響實際參數。例如:
void modify(int num) {num = num * 2;
}
int main() {int value = 5;modify(value);// value 仍為 5,未被修改return 0;
}
????????指針傳遞:通過傳遞變量的地址來實現。函數內部可通過指針修改所指向的實際變量的值。例如:
void modify(int *ptr) {*ptr = *ptr * 2;
}
int main() {int value = 5;modify(&value);// value 變為 10,已被修改return 0;
}
??5.3 可變參數:
????????C 語言允許函數接受可變數量的參數,通過<stdarg.h>頭文件中的宏來實現。例如printf函數就是典型的可變參數函數。
#include <stdarg.h>
#include <stdio.h>
int sum(int count, ...) {va_list args;va_start(args, count);int result = 0;for (int i = 0; i < count; i++) {result += va_arg(args, int);}va_end(args);return result;
}
int main() {int total = sum(3, 1, 2, 3);// total 為 6return 0;
}
????????上述sum函數可接受任意數量的整數參數,并計算它們的和。
六、函數的返回值
? 6.1 返回值類型:
????????函數的返回值類型在函數定義和聲明時指定。返回值類型必須與return語句后表達式的類型兼容。若不兼容,編譯器會進行類型轉換。例如:
double divide(int a, int b) {return (double)a / b;
}
該函數將兩個整數相除,并返回double類型的結果。
??6.2 無返回值函數:
????????若函數無需返回值,使用void作為返回值類型。例如:
void printMessage() {printf("Hello, World!\n");
}
????????此類函數執行完函數體后,直接返回調用處,無需return語句。若使用return,其后不能有返回值表達式。
七、函數指針
? 7.1 定義與使用:
????????函數指針是指向函數的指針變量。通過函數指針可以調用函數,常用于實現回調函數等功能。
// 定義函數指針類型
typedef int (*FuncPtr)(int, int);
int add(int a, int b) {return a + b;
}
int main() {FuncPtr ptr = add;int result = ptr(3, 5);// result 為 8return 0;
}
????????上述代碼中,FuncPtr是一個指向返回值為int,接受兩個int類型參數的函數指針類型。通過FuncPtr定義指針變量ptr,并使其指向add函數,然后通過ptr調用add函數。
??7.2 函數指針作為參數:
????????函數指針可作為其他函數的參數,用于將一個函數的行為傳遞給另一個函數。例如:
int operate(int a, int b, int (*func)(int, int)) {return func(a, b);
}
int add(int a, int b) {return a + b;
}
int subtract(int a, int b) {return a - b;
}
int main() {int result1 = operate(5, 3, add);int result2 = operate(5, 3, subtract);// result1 為 8,result2 為 2return 0;
}
????????operate函數接受兩個整數和一個函數指針作為參數,通過函數指針調用不同的函數進行計算。
八、遞歸函數
? 8.1 遞歸的概念:
????????遞歸函數是指在函數內部調用自身的函數。遞歸通常用于解決可以分解為更小、相似問題的場景。遞歸函數必須有終止條件,否則會導致無限遞歸,最終耗盡系統資源。
??8.2 示例:
????????計算階乘的遞歸函數:
int factorial(int n) {if (n == 0 || n == 1) {return 1;} else {return n * factorial(n - 1);}
}
????????當n為 0 或 1 時,函數返回 1 作為終止條件;否則,通過遞歸調用factorial(n - 1)計算n的階乘。
九、函數的作用域與存儲類
? 9.1 作用域:
????????函數的作用域從函數定義處開始,到文件末尾結束。函數內部定義的變量為局部變量,作用域僅限于函數內部;在函數外部定義的變量為全局變量,作用域為整個源文件。若在函數內部定義了與全局變量同名的局部變量,在函數內部局部變量會覆蓋全局變量。
? 9.2 存儲類:
????????自動存儲類(auto):函數內定義的局部變量默認是自動存儲類,存儲在棧中,函數執行結束時,變量所占用的內存被釋放。
????????靜態存儲類(static):若將局部變量聲明為static,其生命周期會延長至程序結束,且在函數多次調用間保持值不變。靜態局部變量存儲在靜態存儲區。例如:
void increment() {static int count = 0;count++;printf("Count: %d\n", count);
}
????????每次調用increment函數,count的值都會遞增并保留。