1. 函数基础回顾与进阶要点
在C语言中,函数是程序执行的基本单元,也是代码复用的核心手段。上篇我们已经介绍了函数的基本定义、声明和调用方法,本篇将深入探讨函数使用中的几个关键进阶特性。
1.1 函数与数组的交互
数组作为函数参数时,实际上传递的是数组首元素的地址。这种传址方式使得函数内对数组的修改会影响原始数组。下面是一个典型示例:
c复制void modifyArray(int arr[], int size) {
for(int i=0; i<size; i++) {
arr[i] *= 2; // 直接修改原数组元素
}
}
int main() {
int numbers[] = {1, 2, 3, 4, 5};
modifyArray(numbers, 5);
// 此时numbers数组已变为{2, 4, 6, 8, 10}
return 0;
}
注意:当数组作为函数参数时,方括号内的数字可以省略,因为编译器只关心数组的起始地址。数组长度通常需要额外参数传递。
1.2 多维数组的函数传递
对于二维数组,函数声明时需要指定列数(第二维大小),因为编译器需要知道如何计算元素地址:
c复制void processMatrix(int matrix[][3], int rows) {
for(int i=0; i<rows; i++) {
for(int j=0; j<3; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
}
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 变量的存储类别详解
2.1 static关键字的双重作用
static关键字在C语言中有两种完全不同的用法:
- 函数内的静态变量:
c复制void counter() {
static int count = 0; // 只初始化一次
count++;
printf("Count: %d\n", count);
}
// 每次调用counter(),count值会保持递增
- 文件作用域的静态函数/变量:
c复制static void internalFunc() { // 只能在当前文件访问
// 函数实现
}
实际经验:静态局部变量常用于需要保持状态的函数,如计数器、缓存等。但过度使用会导致程序难以理解和调试。
2.2 extern关键字的使用场景
extern用于声明在其他文件中定义的全局变量或函数:
c复制// file1.c
int globalVar = 42;
// file2.c
extern int globalVar; // 声明而非定义
void printVar() {
printf("%d\n", globalVar); // 输出42
}
常见问题:
- 忘记初始化extern变量导致链接错误
- 在多文件中重复定义同名全局变量
3. 函数指针的高级应用
3.1 回调函数实现
函数指针允许我们将函数作为参数传递,实现回调机制:
c复制void processNumbers(int *arr, int size, int (*func)(int)) {
for(int i=0; i<size; i++) {
arr[i] = func(arr[i]);
}
}
int square(int x) { return x*x; }
int increment(int x) { return x+1; }
int main() {
int nums[] = {1,2,3,4,5};
processNumbers(nums, 5, square); // 变为{1,4,9,16,25}
processNumbers(nums, 5, increment); // 变为{2,5,10,17,26}
return 0;
}
3.2 函数指针数组
将多个相关函数组织成数组,可以实现类似"命令模式"的效果:
c复制void cmdA() { printf("执行A操作\n"); }
void cmdB() { printf("执行B操作\n"); }
void cmdC() { printf("执行C操作\n"); }
int main() {
void (*commands[])() = {cmdA, cmdB, cmdC};
int choice;
printf("输入选择(0-2): ");
scanf("%d", &choice);
if(choice >=0 && choice <=2) {
commands[choice]();
}
return 0;
}
4. 递归函数的编写技巧
4.1 经典递归示例
以斐波那契数列为例展示递归实现:
c复制int fibonacci(int n) {
if(n <= 1) return n;
return fibonacci(n-1) + fibonacci(n-2);
}
性能提示:这种简单递归存在大量重复计算,实际应用中应使用记忆化或迭代方法优化。
4.2 尾递归优化
某些编译器支持尾递归优化,可以避免栈溢出:
c复制int factorial(int n, int acc = 1) {
if(n == 0) return acc;
return factorial(n-1, n*acc); // 尾递归形式
}
5. 可变参数函数实现
C语言通过stdarg.h支持可变参数函数,如printf:
c复制#include <stdarg.h>
double average(int count, ...) {
va_list ap;
double sum = 0;
va_start(ap, count);
for(int i=0; i<count; i++) {
sum += va_arg(ap, double);
}
va_end(ap);
return sum/count;
}
// 调用示例
double avg = average(3, 1.5, 2.5, 3.5);
常见陷阱:
- 忘记调用va_start或va_end
- 使用错误的类型调用va_arg
- 参数数量与实际不符
6. 函数设计的最佳实践
6.1 单一职责原则
每个函数应该只完成一个明确的任务。例如,不要将数据读取和处理逻辑混在一个函数中:
c复制// 不好的设计
void processFile(char *filename) {
FILE *fp = fopen(filename, "r");
// 读取文件
// 处理数据
// 输出结果
fclose(fp);
}
// 好的设计
Data readData(char *filename) { /*...*/ }
Result processData(Data data) { /*...*/ }
void outputResult(Result res) { /*...*/ }
6.2 错误处理策略
函数应该通过返回值或参数明确报告错误状态:
c复制int divide(int a, int b, int *result) {
if(b == 0) return -1; // 错误码
*result = a/b;
return 0; // 成功
}
7. 常见问题排查
7.1 栈溢出问题
递归函数或大型局部变量可能导致栈溢出:
c复制void causeOverflow() {
int hugeArray[1000000]; // 可能栈溢出
// ...
}
解决方案:
- 使用动态内存分配(malloc)
- 减小局部变量大小
- 增加栈大小(编译器选项)
7.2 链接错误分析
常见链接错误及解决方法:
-
undefined reference to 'funcName'- 检查函数声明和定义是否一致
- 确保所有源文件都参与链接
-
multiple definition of 'varName'- 全局变量应在头文件中用extern声明
- 在源文件中定义并初始化
8. 性能优化技巧
8.1 inline函数
对于短小的频繁调用函数,可使用inline建议编译器内联展开:
c复制inline int max(int a, int b) {
return a > b ? a : b;
}
注意事项:
- inline只是建议,编译器可能忽略
- 过度使用会导致代码膨胀
- 不适合复杂或有递归调用的函数
8.2 避免不必要的函数调用
在性能关键循环中,减少函数调用开销:
c复制// 优化前
for(int i=0; i<1000000; i++) {
result += smallFunc(i);
}
// 优化后
int temp;
for(int i=0; i<1000000; i++) {
temp = i*i + 2*i + 1; // 直接内联计算
result += temp;
}
9. 现代C标准中的函数特性
9.1 _Generic选择
C11引入的_Generic可以实现简单的函数重载效果:
c复制#define printValue(x) _Generic((x), \
int: printInt, \
double: printDouble, \
char*: printString)(x)
void printInt(int i) { printf("%d\n", i); }
void printDouble(double d) { printf("%f\n", d); }
void printString(char *s) { printf("%s\n", s); }
9.2 匿名函数(C11的受限支持)
通过宏和语句表达式模拟匿名函数:
c复制#define LAMBDA(ret_type, body) ({ ret_type __fn__ body __fn__; })
int (*max)(int, int) = LAMBDA(int, (int a, int b) {
return a > b ? a : b;
});
10. 跨平台开发注意事项
10.1 调用约定
不同平台可能有不同的函数调用约定:
c复制// Windows API常用调用约定
void __stdcall WinAPI_Func(int param);
// Linux常用
void __attribute__((cdecl)) Linux_Func(int param);
10.2 动态库函数导出
创建跨平台动态库时的函数导出方式:
c复制// 头文件中的声明
#ifdef _WIN32
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __attribute__((visibility("default")))
#endif
EXPORT void crossPlatformFunc();
11. 测试与调试技巧
11.1 单元测试框架
使用简单的宏实现基本单元测试:
c复制#define TEST(cond) \
do { \
if(!(cond)) { \
printf("Test failed at %s:%d\n", __FILE__, __LINE__); \
return -1; \
} \
} while(0)
int testAddition() {
TEST(add(2,3) == 5);
TEST(add(-1,1) == 0);
return 0;
}
11.2 函数调用跟踪
通过宏自动记录函数调用:
c复制#ifdef DEBUG
#define ENTER_FUNC() \
printf("--> %s\n", __func__)
#define EXIT_FUNC() \
printf("<-- %s\n", __func__)
#else
#define ENTER_FUNC()
#define EXIT_FUNC()
#endif
void exampleFunc() {
ENTER_FUNC();
// 函数实现
EXIT_FUNC();
}
12. 实战案例:实现简单数学库
综合运用各种函数技术实现数学库:
c复制// mathlib.h
#ifndef MATHLIB_H
#define MATHLIB_H
typedef double (*MathFunc)(double);
double integrate(MathFunc f, double a, double b, int n);
double derivative(MathFunc f, double x, double h);
void tabulate(MathFunc f, double start, double end, double step);
#endif
// mathlib.c
#include "mathlib.h"
double integrate(MathFunc f, double a, double b, int n) {
double h = (b-a)/n;
double sum = 0.5*(f(a)+f(b));
for(int i=1; i<n; i++) {
sum += f(a + i*h);
}
return sum*h;
}
// 其他函数实现...
这个案例展示了如何:
- 使用函数指针作为参数
- 实现数值计算算法
- 组织模块化接口
13. 性能对比:递归 vs 迭代
以阶乘函数为例对比不同实现方式的性能:
c复制#include <stdio.h>
#include <time.h>
// 递归实现
long factorial_rec(int n) {
if(n <= 1) return 1;
return n * factorial_rec(n-1);
}
// 迭代实现
long factorial_iter(int n) {
long result = 1;
for(int i=2; i<=n; i++) {
result *= i;
}
return result;
}
int main() {
clock_t start, end;
double cpu_time_used;
start = clock();
long r1 = factorial_rec(20);
end = clock();
cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("递归耗时: %f 秒\n", cpu_time_used);
start = clock();
long r2 = factorial_iter(20);
end = clock();
cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("迭代耗时: %f 秒\n", cpu_time_used);
return 0;
}
实测结果通常显示迭代版本更快,且不会出现栈溢出问题。但递归版本通常更直观易懂。
14. 函数与多文件项目组织
14.1 头文件设计原则
良好的头文件应包含:
- 函数声明
- 必要的类型定义
- 宏常量
- 简洁的文档注释
示例头文件:
c复制// arrayutils.h
#ifndef ARRAYUTILS_H
#define ARRAYUTILS_H
/**
* 查找数组中的最大值
* @param arr 整型数组
* @param size 数组大小
* @return 最大值
*/
int findMax(const int *arr, int size);
/**
* 反转数组元素顺序
* @param arr 整型数组
* @param size 数组大小
*/
void reverseArray(int *arr, int size);
#endif
14.2 防止多重包含
使用预处理指令防止头文件被多次包含:
c复制#ifndef UNIQUE_HEADER_NAME
#define UNIQUE_HEADER_NAME
// 头文件内容
#endif
15. 函数文档规范
良好的文档应该包含:
- 功能描述
- 参数说明
- 返回值说明
- 可能的错误条件
- 使用示例
Doxygen格式示例:
c复制/**
* @brief 计算两个数的最大公约数
*
* @param a 第一个整数
* @param b 第二个整数
* @return int 最大公约数
*
* @note 使用欧几里得算法实现
* @warning 参数不能同时为0
*/
int gcd(int a, int b) {
while(b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
16. 函数安全编程
16.1 缓冲区溢出防护
处理字符串时要特别注意缓冲区边界:
c复制void safeCopy(char *dest, const char *src, size_t destSize) {
if(destSize == 0) return;
size_t i;
for(i=0; i<destSize-1 && src[i]!='\0'; i++) {
dest[i] = src[i];
}
dest[i] = '\0'; // 确保终止符
}
16.2 参数校验
对所有外部输入进行验证:
c复制int safeDivide(int a, int b, int *result) {
if(b == 0) {
return -1; // 错误码
}
if(result == NULL) {
return -2; // 无效指针
}
*result = a / b;
return 0; // 成功
}
17. 函数与内存管理
17.1 返回动态分配的内存
当函数需要返回新分配的内存时:
c复制char *createGreeting(const char *name) {
if(name == NULL) return NULL;
size_t len = strlen("Hello, ") + strlen(name) + strlen("!") + 1;
char *greeting = malloc(len);
if(greeting == NULL) return NULL;
snprintf(greeting, len, "Hello, %s!", name);
return greeting;
}
// 调用者负责释放内存
char *g = createGreeting("World");
if(g != NULL) {
printf("%s\n", g);
free(g);
}
17.2 回调函数中的内存管理
当函数接受回调函数时,要明确内存所有权:
c复制typedef void (*DataProcessor)(int *data, size_t size);
void processWithCallback(DataProcessor processor) {
int *data = malloc(100 * sizeof(int));
if(data == NULL) return;
// 填充数据...
processor(data, 100);
// 明确文档说明:回调函数不应释放data
free(data);
}
18. 函数与多线程
18.1 线程安全函数
编写可重入函数的基本原则:
- 避免使用静态局部变量
- 不依赖全局状态
- 使用局部变量存储中间结果
c复制// 非线程安全版本
char *timestamp() {
static char buffer[20];
time_t now = time(NULL);
strftime(buffer, 20, "%Y-%m-%d %H:%M:%S", localtime(&now));
return buffer;
}
// 线程安全版本
void timestamp_safe(char *buffer, size_t size) {
time_t now = time(NULL);
strftime(buffer, size, "%Y-%m-%d %H:%M:%S", localtime(&now));
}
18.2 回调函数与线程
在多线程环境中使用回调函数的注意事项:
c复制#include <pthread.h>
typedef void (*ThreadCallback)(void *);
struct ThreadArgs {
ThreadCallback callback;
void *userData;
};
void *threadWrapper(void *arg) {
struct ThreadArgs *args = (struct ThreadArgs *)arg;
args->callback(args->userData);
return NULL;
}
void startThread(ThreadCallback cb, void *userData) {
pthread_t thread;
struct ThreadArgs args = {cb, userData};
pthread_create(&thread, NULL, threadWrapper, &args);
// 注意:args不能是局部变量,因为线程可能在其作用域外运行
}
19. 函数式编程风格
虽然C不是函数式语言,但可以模拟一些函数式特性:
19.1 高阶函数
c复制typedef int (*IntOperator)(int, int);
int applyOperator(IntOperator op, int a, int b) {
return op(a, b);
}
int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }
int main() {
printf("%d\n", applyOperator(add, 3, 4)); // 7
printf("%d\n", applyOperator(multiply, 3, 4)); // 12
return 0;
}
19.2 闭包模拟
通过结构体和函数指针模拟闭包:
c复制typedef struct {
int base;
int (*func)(struct Closure*, int);
} Closure;
int closureFunc(Closure *self, int x) {
return self->base + x;
}
Closure makeAdder(int base) {
Closure c = {base, closureFunc};
return c;
}
int main() {
Closure add5 = makeAdder(5);
printf("%d\n", add5.func(&add5, 3)); // 8
return 0;
}
20. 嵌入式系统中的函数优化
20.1 避免浮点运算
在无FPU的系统中,使用定点数代替浮点数:
c复制typedef int32_t fixed_t;
#define FIXED_SHIFT 8
#define FLOAT_TO_FIXED(f) ((fixed_t)((f) * (1 << FIXED_SHIFT)))
#define FIXED_TO_FLOAT(f) ((float)(f) / (1 << FIXED_SHIFT))
fixed_t fixedMultiply(fixed_t a, fixed_t b) {
return (a * b) >> FIXED_SHIFT;
}
20.2 中断服务函数
ISR函数的特殊要求:
- 尽量简短
- 避免阻塞操作
- 声明为volatile
c复制volatile int interruptFlag = 0;
void __attribute__((interrupt)) timerISR(void) {
interruptFlag = 1;
// 清除中断标志等必要操作
}
21. 函数与硬件交互
21.1 内存映射IO
通过指针直接访问硬件寄存器:
c复制#define GPIO_BASE (volatile uint32_t *)0x40020000
#define GPIO_SET *(GPIO_BASE + 0)
#define GPIO_CLEAR *(GPIO_BASE + 1)
void setLed(int state) {
if(state) {
GPIO_SET = 0x01; // 设置第0位
} else {
GPIO_CLEAR = 0x01; // 清除第0位
}
}
21.2 内联汇编
在C函数中嵌入汇编代码:
c复制void delay(unsigned int cycles) {
__asm__ volatile (
"1: subs %0, %0, #1\n"
" bne 1b"
: "+r" (cycles)
);
}
22. 函数与算法实现
22.1 排序算法实现
以快速排序为例展示算法函数:
c复制void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int partition(int arr[], int low, int high) {
int pivot = arr[high];
int i = low - 1;
for(int j=low; j<high; j++) {
if(arr[j] < pivot) {
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i+1], &arr[high]);
return i+1;
}
void quickSort(int arr[], int low, int high) {
if(low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi-1);
quickSort(arr, pi+1, high);
}
}
22.2 查找算法实现
二分查找的标准实现:
c复制int binarySearch(int arr[], int size, int target) {
int left = 0;
int right = size - 1;
while(left <= right) {
int mid = left + (right - left) / 2;
if(arr[mid] == target) {
return mid;
} else if(arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1; // 未找到
}
23. 函数与数据结构
23.1 链表操作
基本链表操作函数集:
c复制typedef struct Node {
int data;
struct Node *next;
} Node;
Node *createNode(int data) {
Node *newNode = malloc(sizeof(Node));
if(newNode != NULL) {
newNode->data = data;
newNode->next = NULL;
}
return newNode;
}
void insertAtHead(Node **head, int data) {
Node *newNode = createNode(data);
if(newNode != NULL) {
newNode->next = *head;
*head = newNode;
}
}
void printList(Node *head) {
while(head != NULL) {
printf("%d ", head->data);
head = head->next;
}
printf("\n");
}
23.2 二叉树遍历
递归实现二叉树遍历:
c复制typedef struct TreeNode {
int value;
struct TreeNode *left;
struct TreeNode *right;
} TreeNode;
void inorderTraversal(TreeNode *root) {
if(root == NULL) return;
inorderTraversal(root->left);
printf("%d ", root->value);
inorderTraversal(root->right);
}
void preorderTraversal(TreeNode *root) {
if(root == NULL) return;
printf("%d ", root->value);
preorderTraversal(root->left);
preorderTraversal(root->right);
}
void postorderTraversal(TreeNode *root) {
if(root == NULL) return;
postorderTraversal(root->left);
postorderTraversal(root->right);
printf("%d ", root->value);
}
24. 函数与文件操作
24.1 文本文件处理
常见文本处理函数:
c复制int countLines(const char *filename) {
FILE *file = fopen(filename, "r");
if(file == NULL) return -1;
int count = 0;
char ch;
while((ch = fgetc(file)) != EOF) {
if(ch == '\n') count++;
}
fclose(file);
return count;
}
void copyFile(const char *src, const char *dest) {
FILE *srcFile = fopen(src, "rb");
FILE *destFile = fopen(dest, "wb");
if(srcFile == NULL || destFile == NULL) {
// 错误处理
return;
}
char buffer[1024];
size_t bytes;
while((bytes = fread(buffer, 1, sizeof(buffer), srcFile)) > 0) {
fwrite(buffer, 1, bytes, destFile);
}
fclose(srcFile);
fclose(destFile);
}
24.2 二进制数据读写
结构体读写函数:
c复制typedef struct {
int id;
char name[50];
float score;
} Student;
int saveStudent(const char *filename, Student *s) {
FILE *file = fopen(filename, "wb");
if(file == NULL) return 0;
int success = fwrite(s, sizeof(Student), 1, file) == 1;
fclose(file);
return success;
}
int loadStudent(const char *filename, Student *s) {
FILE *file = fopen(filename, "rb");
if(file == NULL) return 0;
int success = fread(s, sizeof(Student), 1, file) == 1;
fclose(file);
return success;
}
25. 函数与字符串处理
25.1 安全字符串函数
实现安全的字符串操作:
c复制size_t safeStrlen(const char *s, size_t maxlen) {
size_t len = 0;
while(len < maxlen && s[len] != '\0') {
len++;
}
return len;
}
int safeStrcpy(char *dest, const char *src, size_t destSize) {
if(destSize == 0) return -1;
size_t i;
for(i=0; i<destSize-1 && src[i]!='\0'; i++) {
dest[i] = src[i];
}
dest[i] = '\0';
return (src[i] == '\0') ? 0 : -2; // 0=完整复制,-2=截断
}
25.2 常用字符串工具函数
扩展标准库的字符串函数:
c复制char *strtrim(char *str) {
char *end;
// 去除前导空格
while(isspace((unsigned char)*str)) str++;
if(*str == '\0') return str;
// 去除尾部空格
end = str + strlen(str) - 1;
while(end > str && isspace((unsigned char)*end)) end--;
// 写入终止符
*(end+1) = '\0';
return str;
}
int strcontains(const char *str, const char *substr) {
return strstr(str, substr) != NULL;
}
26. 函数与时间处理
26.1 高精度计时
实现性能测试用的计时函数:
c复制#include <time.h>
typedef struct {
struct timespec start;
struct timespec end;
} Timer;
void timerStart(Timer *t) {
clock_gettime(CLOCK_MONOTONIC, &t->start);
}
void timerStop(Timer *t) {
clock_gettime(CLOCK_MONOTONIC, &t->end);
}
double timerElapsed(Timer *t) {
return (t->end.tv_sec - t->start.tv_sec) +
(t->end.tv_nsec - t->start.tv_nsec) / 1e9;
}
26.2 日期时间转换
常用日期处理函数:
c复制void formatTime(time_t rawtime, char *buffer, size_t size) {
struct tm *timeinfo = localtime(&rawtime);
strftime(buffer, size, "%Y-%m-%d %H:%M:%S", timeinfo);
}
int isLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
int dayOfYear(int year, int month, int day) {
static const int daysInMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
int dayCount = day;
for(int m=0; m<month-1; m++) {
dayCount += daysInMonth[m];
if(m == 1 && isLeapYear(year)) dayCount++;
}
return dayCount;
}
27. 函数与数学计算
27.1 数值积分
实现梯形法数值积分:
c复制double integrate(double (*f)(double), double a, double b, int n) {
double h = (b - a) / n;
double sum = 0.5 * (f(a) + f(b));
for(int i=1; i<n; i++) {
sum += f(a + i * h);
}
return sum * h;
}
27.2 随机数生成
更高质量的随机数函数:
c复制unsigned long xorshift32(unsigned long *state) {
unsigned long x = *state;
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
return *state = x;
}
double randomDouble(unsigned long *state) {
return (double)xorshift32(state) / (double)ULONG_MAX;
}
28. 函数与网络编程
28.1 套接字辅助函数
简化套接字操作的函数:
c复制int createSocket() {
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0) {
perror("socket creation failed");
return -1;
}
// 设置SO_REUSEADDR选项
int opt = 1;
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
perror("setsockopt failed");
close(sock);
return -1;
}
return sock;
}
int connectToServer(int sock, const char *ip, int port) {
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
if(inet_pton(AF_INET, ip, &serv_addr.sin_addr) <= 0) {
perror("invalid address");
return -1;
}
if(connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("connection failed");
return -1;
}
return 0;
}
28.2 数据发送接收
带超时的数据收发函数:
c复制int sendWithTimeout(int sock, const void *buf, size_t len, int timeoutSec) {
fd_set writefds;
FD_ZERO(&writefds);
FD_SET(sock, &writefds);
struct timeval tv;
tv.tv_sec = timeoutSec;
tv.tv_usec = 0;
if(select(sock+1, NULL, &writefds, NULL, &tv) <= 0) {
return -1; // 超时或错误
}
return send(sock, buf, len, 0);
}
int recvWithTimeout(int sock, void *buf, size_t len, int timeoutSec) {
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
struct timeval tv;
tv.tv_sec = timeoutSec;
tv.tv_usec = 0;
if(select(sock+1, &readfds, NULL, NULL, &tv) <= 0) {
return -1; // 超时或错误
}
return recv(sock, buf, len, 0);
}
29. 函数与图形编程
29.1 简单图形绘制
基于控制台的图形函数:
c复制void drawLine(int x1, int y1, int x2, int y2, char ch) {
int dx = abs(x2 - x1);
int dy = abs(y2 - y1);
int sx = (x1 < x2) ? 1 : -1;
int sy = (y1 < y2) ? 1 : -1;
int err = dx - dy;
while(1) {
// 在(x1,y1)位置绘制字符
printf("\033[%d;%dH%c", y1+1, x1+1, ch);
if(x1 == x2 && y1 == y2) break;
int e2 = 2 * err;
if(e2 > -dy) {
err -= dy;
x1 += sx;
}
if(e2 < dx) {
err += dx;
y1 += sy;
}
}
}
void clearScreen() {
printf("\033[2J\033[H");
}
29.2 控制台动画
简单的动画效果函数:
c复制void animateProgress(int total, int delayMs) {
for(int i=0; i<=total; i++) {
printf("\r[");
int pos = (i * 50) / total;
for(int j=0; j<50; j++) {
if(j < pos) printf("=");
else if(j == pos) printf(">");
else printf(" ");
}
printf("] %d%%", (i * 100) / total);
fflush(stdout);
usleep(delayMs * 1000);
}
printf("\n");
}
30. 函数设计模式
30.1 工厂函数
创建不同类型对象的工厂函数:
c复制typedef struct {
void (*draw)(void);
} Shape;
void drawCircle() { printf("Drawing circle\n"); }
void drawSquare() { printf("Drawing square\n"); }
Shape *createShape(const char *type) {
if(strcmp(type, "circle") == 0) {
Shape *circle = malloc(sizeof(Shape));
circle->draw = drawCircle;
return circle;
} else if(strcmp(type, "square") == 0) {
Shape *square = malloc(sizeof(Shape));
square->draw = drawSquare;
return square;
}
return NULL;
}
30.2 策略模式
通过函数指针实现策略模式:
c复制typedef int (*SortStrategy)(int *, int);
int bubbleSort(int *arr, int size) {
// 实现冒泡排序
return 0;
}
int quickSortWrapper(int *arr, int size) {
// 实现快速排序
return 0;
}
void sortArray(int *arr, int
