1笔记
一、函数基础概念
1. 函数定义
-
作用:将代码模块化,实现代码复用、逻辑封装和分层设计。
-
核心特点:
-
每个函数完成独立任务。
-
通过参数传递数据,通过返回值输出结果。
-
函数之间通过调用关系协作。
-
二、函数语法
1. 函数定义格式
返回类型 函数名(参数列表) {
// 函数体
return 返回值; // 若返回类型为 void,可省略 return
}
示例:加法函数
int add(int a, int b) {
return a + b;
}
2. 函数声明(原型)
-
作用:告诉编译器函数的存在性(用于分离式编译)。
-
格式:
返回类型 函数名(参数类型列表);
(参数名可省略,但建议保留以提高可读性)
示例:
int add(int, int); // 声明
// 或
int add(int a, int b); // 推荐写法
三、参数传递机制
1. 值传递(默认行为)
-
规则:函数内部操作的是参数的副本,不影响原始数据。
-
示例:
void swap(int x, int y) { int temp = x; x = y; y = temp; // 仅交换副本,不影响外部变量 }
2. 指针传递(模拟“引用传递”)
-
规则:通过指针直接操作原始数据的内存地址。
-
示例:
void swap(int *x, int *y) { int temp = *x; *x = *y; *y = temp; // 实际修改外部变量 }
3. 数组作为参数
-
特点:数组名退化为指针,传递的是数组首地址。
-
示例:
void printArray(int arr[], int size) { // 等价于 int *arr for (int i = 0; i < size; i++) { printf("%d ", arr[i]); } }
四、返回值
1. 基本规则
-
返回类型:必须与函数声明一致(
void
表示无返回值)。 -
返回值限制:
-
可以返回基本类型(
int
、float
等)、结构体、指针。 -
不可返回局部变量的地址(函数结束局部变量被销毁,导致悬垂指针)。
-
2. 多返回值模拟
-
方法 1:通过指针参数修改外部变量。
-
方法 2:返回结构体(包含多个数据)。
五、作用域与生命周期
1. 局部变量
-
作用域:仅在函数内部有效。
-
生命周期:函数调用时创建,函数结束时销毁。
2. 全局变量
-
作用域:从定义位置到文件末尾。
-
生命周期:程序运行期间始终存在。
3. 静态局部变量(static
)
-
特点:
-
作用域仍为函数内部。
-
生命周期延长至程序结束(值在多次调用间保留)。
-
-
示例:
void counter() { static int count = 0; // 只初始化一次 count++; printf("Count: %d\n", count); }
六、递归函数
1. 核心条件
-
基线条件(Base Case):递归终止条件。
-
递归条件(Recursive Case):问题分解为更小规模的同类问题。
2. 示例:阶乘计算
int factorial(int n) {
if (n <= 1) { // 基线条件
return 1;
} else { // 递归条件
return n * factorial(n - 1);
}
}
3. 注意事项
-
栈溢出风险:递归深度过大可能导致栈空间耗尽。
-
效率问题:递归可能比循环更耗资源(函数调用开销)。
2.作业
1.可变参实现my_printf
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
// 自定义简化版 printf 函数
void my_printf(const char *format, ...) {
va_list args; // 定义可变参数列表
va_start(args, format); // 初始化参数列表
while (*format != '\0') { // 遍历格式字符串
if (*format == '%') { // 遇到格式符
format++; // 跳过 '%'
// 根据格式符处理不同类型
switch (*format) {
case 'd': { // 处理整数
int num = va_arg(args, int);
printf("%d", num);
break;
}
case 'f': { // 处理浮点数(默认保留两位小数)
double num = va_arg(args, double);
printf("%.2f", num);
break;
}
case 's': { // 处理字符串
char *str = va_arg(args, char*);
printf("%s", str);
break;
}
case 'c': { // 处理字符
char ch = (char)va_arg(args, int); // char 会被提升为 int
printf("%c", ch);
break;
}
case '%': { // 输出 '%' 自身
putchar('%');
break;
}
default: { // 未知格式符直接输出
putchar('%');
putchar(*format);
}
}
} else { // 普通字符直接输出
putchar(*format);
}
format++; // 继续下一个字符
}
va_end(args); // 清理参数列表
}
int main() {
// 测试
my_printf("整数:%d,浮点数:%f,字符:%c,字符串:%s\n",50,2.1,'a',"hahaha");
return 0;
}
2.回调函数结构体排序
#include <stdio.h>
#include <stdlib.h>
// 定义学生结构体
typedef struct {
char name[50];
int score;
} Student;
// 比较函数:按分数降序排序
int compareByScore(const void *a, const void *b) {
const Student *s1 = (const Student*)a;
const Student *s2 = (const Student*)b;
return s2->score - s1->score; // 降序:大值在前
}
// 打印学生数组
void printStudents(const Student *students, int size) {
for (int i = 0; i < size; i++) {
printf("Name: %-10s | Score: %3d\n", students[i].name, students[i].score);
}
printf("--------------------------\n");
}
int main() {
// 初始化学生数组
Student students[] = {
{"张三", 85},
{"李四", 92},
{"小明", 78},
{"小红", 92} // 分数相同,测试稳定性
};
int size = sizeof(students) / sizeof(students[0]);
printf("Original order:\n");
printStudents(students, size);
// 按分数降序排序
qsort(students, size, sizeof(Student), compareByScore);
printf("按分数降序(排序):\n");
printStudents(students, size);
return 0;
}