1. C語言中的參數基本知識
什麼是參數
參數是指在函式被呼叫時,從外部傳遞給函式的資料。透過使用參數,函式可以接收各種不同的值作為輸入,並依據這些值進行相應處理。熟悉 C 語言中的參數使用方式,是提升程式重用性與彈性不可或缺的一步。
實際參數與形式參數
由呼叫端傳入的值稱為實際參數(實參),而在函式定義中接收該值的則稱為形式參數(形參)。例如,PrintScore(score);
裡的 score
是實際參數,而 void PrintScore(int score)
的 score
則是形式參數。正確理解兩者的差異,對正確使用函式非常重要。
2. 實際參數與形式參數的差異
實際參數
實際參數是在呼叫函式時實際傳遞的值。例如,PrintScore(100);
中的 100
就是實際參數。它會被傳遞給函式,並在該函式內部使用。
形式參數
形式參數是在函式定義時所指定的變數名稱。形參在函式內部代表實參的值,但無法在函式外部修改。例如,void PrintScore(int score)
中的 score
就是形式參數。
3. 參數的傳遞方式
值傳遞(Pass by Value)
值傳遞是將實際參數的值複製給形式參數。在此情況下,即使函式內部改變形參的值,也不會影響到呼叫端的實參。請參考以下範例:
void LevelUp(int lv) {
lv++;
}
int main() {
int level = 1;
LevelUp(level);
printf("Level: %dn", level); // 輸出: Level: 1
}
本例中,雖然 LevelUp
內的 lv
有被加一,但 main
函式裡的 level
並未受到影響。值傳遞的優點是能保護呼叫端資料,但如果傳遞大量資料時,記憶體使用量會增加,須留意效能。
指標傳遞(Pass by Pointer)
指標傳遞是將實參的記憶體位址傳給形參。這讓函式內部可以直接修改實參的值。
void LevelUp(int *plv) {
(*plv)++;
}
int main() {
int level = 1;
LevelUp(&level);
printf("Level: %dn", level); // 輸出: Level: 2
}
這個例子中,LevelUp
函式可以直接改變 level
變數的值。指標傳遞的好處是可以在函式間回傳多個結果,但若指標操作不當,易導致 bug 或記憶體洩漏,需小心處理。
4. 參數數量與回傳值的組合
有參數、無回傳值
此類型函式有參數,但不回傳處理結果。例如 void PrintScore(int score)
,僅負責顯示分數。
無參數、有回傳值
此類型函式無需傳入參數,僅回傳處理結果。例如 int GetCurrentScore()
,計算後回傳目前分數。
有參數、有回傳值
同時有參數也有回傳值。例如 int Add(int a, int b)
,傳入兩數,回傳加總。這類函式彈性高,應用廣泛。
5. 遞迴呼叫與參數
什麼是遞迴呼叫
遞迴呼叫是函式內部再次呼叫自己,用來將複雜問題拆分為較小部分逐步解決。若遞迴結束條件設計不當,容易發生堆疊溢位(Stack Overflow)。
遞迴呼叫範例
下例說明如何利用參數遞迴將數字不斷除以 2:
int funcA(int num) {
if(num % 2 != 0) {
return num;
}
return funcA(num / 2);
}
int main() {
int result = funcA(20);
printf("Result: %dn", result); // 輸出: Result: 5
}
此例中,funcA
會不斷將傳入的數字除以 2,直到遇到奇數時回傳。遞迴雖方便,但須正確設定結束條件,否則易陷入無窮迴圈。
6. 函數樣式巨集與參數
什麼是函數樣式巨集
函數樣式巨集是帶有參數的巨集,在編譯階段會將程式碼做置換,能提升執行效能。
函數樣式巨集範例
以下為取得陣列元素數量的巨集範例:
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
int main() {
int arr[10];
printf("Array size: %dn", ARRAY_SIZE(arr)); // 輸出: Array size: 10
}
函數樣式巨集在編譯前直接置換,不會產生執行時的額外負擔。但因未做型別檢查,可用於多種資料型態,需注意避免預期外行為。
7. C語言標準函式庫中的函式與參數
善用標準函式庫
C 語言提供了眾多標準函式,這些函式都利用參數來完成各種操作。例如 printf
函式就是一個可變參數函式,可依格式字串顯示資料。
標準函式庫範例
以下是 printf
的使用例子:
printf("Name: %s, Age: %dn", "Alice", 30); // 輸出: Name: Alice, Age: 30
本例利用 printf
同時顯示字串與數值。善用標準函式,可讓程式更易讀且高效。
8. 小結
可變參數的應用
C 語言允許函式接收數量不固定的參數,這稱為可變參數。用省略號(...
)在定義時標記。最知名的例子是 printf
,能依格式字串傳入任意數量參數。
可變參數範例
以下範例說明如何使用可變參數計算多個整數的總和:
#include <stdarg.h>
#include <stdio.h>
int sum(int count, ...) {
va_list args;
va_start(args, count);
int total = 0;
for (int i = 0; i < count; i++) {
total += va_arg(args, int);
}
va_end(args);
return total;
}
int main() {
printf("Sum: %dn", sum(4, 1, 2, 3, 4)); // 輸出: Sum: 10
}
本例中,sum
可接收任意數量的整數參數並回傳總和。使用 va_list
、va_start
、va_arg
、va_end
來處理可變參數。
注意事項
使用可變參數時,必須確保參數數量與型別正確。若呼叫與定義不符,易發生預期外錯誤或程式崩潰。
實用案例與參數的應用
參數的有效使用方式
善用參數能提升程式碼可讀性與重用性。例如,當多個函式需處理同筆資料時,比起使用全域變數,直接透過參數傳遞可提升函式獨立性並降低彼此影響。
記憶體效率與效能
若需傳遞大量資料,建議採用指標傳遞以節省記憶體。例如,傳遞大型陣列或結構時,值傳遞會複製整份資料,指標傳遞則僅傳遞位址,有助於提升效率。
程式設計最佳實踐
設計函式時,建議謹慎規劃所需參數的數量與型別。避免傳遞不必要參數,以免增加複雜度與錯誤風險。將所有所需資料明確地當作參數傳入,有助於提升程式碼的可讀性與維護性。
9. 參數相關進階技巧
回呼函式(Callback)
回呼函式指將函式當作參數傳遞給其他函式,並在特定時機呼叫。這種技巧常用於事件驅動或非同步程式設計中,能靈活擴展功能。
#include <stdio.h>
void executeCallback(void (*callback)(int)) {
callback(10);
}
void printValue(int val) {
printf("Value: %dn", val);
}
int main() {
executeCallback(printValue); // 輸出: Value: 10
}
這個例子中,將 printValue
作為回呼函式傳入 executeCallback
,並於該函式中執行。
函式指標
函式指標可讓函式像變數一樣被操作、傳遞。能根據需要動態指定要呼叫的函式,靈活性高,是進階 C 語言技巧。
#include <stdio.h>
int add(int a, int b) {
return a + b;
}
int main() {
int (*operation)(int, int) = add;
printf("Result: %dn", operation(2, 3)); // 輸出: Result: 5
}
本例中,add
被指定給函式指標 operation
,再經由指標呼叫。
10. 函式參數與記憶體管理
動態記憶體與參數
在 C 語言中,可利用 malloc
、free
進行動態記憶體分配。若將動態分配的記憶體指標作為參數傳遞,須特別注意記憶體管理。
#include <stdlib.h>
#include <stdio.h>
void allocateMemory(int **ptr, int size) {
*ptr = (int *)malloc(size * sizeof(int));
}
int main() {
int *arr;
allocateMemory(&arr, 5);
for (int i = 0; i < 5; i++) {
arr[i] = i + 1;
}
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]); // 輸出: 1 2 3 4 5
}
free(arr); // 釋放記憶體
}
此例中,allocateMemory
動態分配記憶體,並將指標傳遞給主程式。若未妥善釋放,容易發生記憶體洩漏,需格外小心。