函數指針詳解
函數指針詳解
函數指針是C/C++中非常重要的概念,它允許程序在運行時動態地調用不同的函數。
1. 基本概念
函數指針是指向函數的指針變量,它存儲的是函數的入口地址。
2. 函數指針的聲明
基本語法
返回類型 (*指針變量名)(參數類型列表);
示例
// 聲明一個指向函數的指針,該函數無參數,返回int int (*func_ptr)(void); // 聲明一個指向函數的指針,該函數有兩個int參數,返回int int (*operation)(int, int); // 聲明一個指向函數的指針,該函數有char*參數,返回void void (*print_func)(char*);
3. 函數指針的使用
基本用法示例
c #include <stdio.h> // 幾個簡單的函數 int add(int a, int b) { return a + b; } int subtract(int a, int b) { return a - b; } int multiply(int a, int b) { return a * b; } int main() { // 聲明函數指針 int (*operation)(int, int); // 指向add函數 operation = add; printf("10 + 5 = %d\n", operation(10, 5)); // 指向subtract函數 operation = subtract; printf("10 - 5 = %d\n", operation(10, 5)); // 指向multiply函數 operation = multiply; printf("10 * 5 = %d\n", operation(10, 5)); return 0; }
4. 函數指針的初始化
多種初始化方式
c #include <stdio.h> void hello() { printf("Hello!\n"); } void world() { printf("World!\n"); } int main() { // 方式1:先聲明后賦值 void (*func1)(void); func1 = hello; func1(); // 方式2:聲明時初始化 void (*func2)(void) = world; func2(); // 方式3:使用地址運算符(可選) void (*func3)(void) = &hello; func3(); return 0; }
5. 函數指針作為參數
回調函數示例
c #include <stdio.h> // 回調函數類型 typedef void (*Callback)(int); // 接受回調函數作為參數的函數 void process_numbers(int arr[], int size, Callback callback) { for (int i = 0; i < size; i++) { callback(arr[i]); // 調用回調函數 } } // 不同的回調函數實現 void print_number(int num) { printf("Number: %d\n", num); } void print_square(int num) { printf("Square of %d: %d\n", num, num * num); } void print_double(int num) { printf("Double of %d: %d\n", num, num * 2); } int main() { int numbers[] = {1, 2, 3, 4, 5}; int size = sizeof(numbers) / sizeof(numbers[0]); printf("原始數字:\n"); process_numbers(numbers, size, print_number); printf("\n平方:\n"); process_numbers(numbers, size, print_square); printf("\n兩倍:\n"); process_numbers(numbers, size, print_double); return 0; }
6. 函數指針作為返回值
函數工廠模式
c #include <stdio.h> // 幾個操作函數 int add(int a, int b) { return a + b; } int sub(int a, int b) { return a - b; } int mul(int a, int b) { return a * b; } // 返回函數指針的函數 int (*get_operation(char op))(int, int) { switch (op) { case '+': return add; case '-': return sub; case '*': return mul; default: return NULL; } } int main() { int a = 10, b = 5; char operators[] = {'+', '-', '*'}; for (int i = 0; i < 3; i++) { int (*operation)(int, int) = get_operation(operators[i]); if (operation) { printf("%d %c %d = %d\n", a, operators[i], b, operation(a, b)); } } return 0; }
7. 使用typedef簡化函數指針
typedef用法
c
#include <stdio.h> // 使用typedef定義函數指針類型 typedef int (*MathOperation)(int, int); typedef void (*PrintFunction)(char*); // 函數實現 int add(int a, int b) { return a + b; } int multiply(int a, int b) { return a * b; } void print_upper(char* str) { while (*str) { putchar(toupper(*str++)); } putchar('\n'); } int main() { // 使用typedef后的聲明更簡潔 MathOperation op1 = add; MathOperation op2 = multiply; PrintFunction printer = print_upper; printf("加法: %d\n", op1(5, 3)); printf("乘法: %d\n", op2(5, 3)); printer("hello world"); return 0; }
8. 函數指針數組
命令表模式
使用簡化模式方便查看,通常情況下的使用如下
聲明 含義 unsigned char *fun(void) 函數,返回 unsigned char* unsigned char (*fun)(void) 函數指針,指向返回 unsigned char 的函數 unsigned char (*fun[])(void) 函數指針數組 unsigned char (*const fun[])(void) 常量函數指針數組
// 命令處理器表 void (*commands[])(void) = { cmd_help, cmd_start, cmd_stop, cmd_status, NULL // 結束標記 }; // 狀態機處理函數表 void (*state_handlers[])(void) = { state_idle, state_running, state_paused, state_error };
#include <stdio.h> // 命令函數 void cmd_help() { printf("顯示幫助信息\n"); } void cmd_start() { printf("啟動服務\n"); } void cmd_stop() { printf("停止服務\n"); } void cmd_status() { printf("顯示狀態\n"); } void cmd_exit() { printf("退出程序\n"); }
// 使用typedef簡化 typedef void (*Command)(); int main() { // 函數指針數組 Command commands[] = {cmd_help, cmd_start, cmd_stop, cmd_status, cmd_exit}; const char* command_names[] = {"help", "start", "stop", "status", "exit"}; int command_count = sizeof(commands) / sizeof(commands[0]); // 模擬命令執行 for (int i = 0; i < command_count; i++) { printf("執行命令 '%s': ", command_names[i]); commands[i](); } return 0; }
9. 實際應用場景
場景1:排序算法選擇
c
#include <stdio.h>
#include <stdlib.h>
typedef int (*CompareFunc)(const void*, const void*);
// 不同的比較函數
int ascending(const void* a, const void* b) {
return (*(int*)a - *(int*)b);
}
int descending(const void* a, const void* b) {
return (*(int*)b - *(int*)a);
}
void sort_array(int arr[], int size, CompareFunc compare) {
qsort(arr, size, sizeof(int), compare);
}
int main() {
int numbers[] = {5, 2, 8, 1, 9};
int size = sizeof(numbers) / sizeof(numbers[0]);
printf("原數組: ");
for (int i = 0; i < size; i++) printf("%d ", numbers[i]);
printf("\n");
// 升序排序
sort_array(numbers, size, ascending);
printf("升序排序: ");
for (int i = 0; i < size; i++) printf("%d ", numbers[i]);
printf("\n");
// 降序排序
sort_array(numbers, size, descending);
printf("降序排序: ");
for (int i = 0; i < size; i++) printf("%d ", numbers[i]);
printf("\n");
return 0;
}
場景2:狀態機實現
c
#include <stdio.h>
typedef void (*StateHandler)();
void state_idle() { printf("空閑狀態 - 等待命令\n"); }
void state_processing() { printf("處理狀態 - 正在工作\n"); }
void state_error() { printf("錯誤狀態 - 需要處理錯誤\n"); }
int main() {
StateHandler current_state = state_idle;
int input;
while (1) {
current_state();
printf("輸入狀態 (0:空閑, 1:處理, 2:錯誤, -1:退出): ");
scanf("%d", &input);
if (input == -1) break;
switch (input) {
case 0: current_state = state_idle; break;
case 1: current_state = state_processing; break;
case 2: current_state = state_error; break;
default: printf("無效輸入\n");
}
}
return 0;
}
10. 注意事項
類型安全
c
// 錯誤的函數指針賦值
void func_void(void) { }
int func_int(int) { return 0; }
// 以下會導致編譯錯誤或未定義行為
// void (*wrong_ptr)(void) = func_int; // 錯誤:類型不匹配
// int (*wrong_ptr2)(int) = func_void; // 錯誤:類型不匹配
空指針檢查
c
#include <stdio.h>
int add(int a, int b) { return a + b; }
int main() {
int (*func_ptr)(int, int) = NULL;
// 在使用前檢查指針是否為空
if (func_ptr != NULL) {
func_ptr(1, 2); // 安全調用
} else {
printf("函數指針為空!\n");
}
// 正確賦值后使用
func_ptr = add;
if (func_ptr) { // 簡寫的空指針檢查
printf("結果: %d\n", func_ptr(3, 4));
}
return 0;
}
總結
函數指針是C/C++中強大的特性,主要用于:
-
回調函數機制
-
策略模式實現
-
命令模式
-
狀態機
-
動態函數選擇
-
插件架構
掌握函數指針可以讓你寫出更加靈活和可擴展的代碼!
浙公網安備 33010602011771號