Appearance
函数
函数是C语言程序的基本组成单位,用于实现特定功能的代码块。通过函数可以将程序分解为多个模块,提高代码的可读性和复用性。本章将详细介绍C语言函数的定义和使用。
函数基础
函数的定义
c
/*
* 函数的定义
*/
#include <stdio.h>
/*
* 函数的基本结构:
* 返回类型 函数名(参数列表)
* {
* 函数体
* return 返回值;
* }
*/
/* 无参数无返回值的函数 */
void say_hello(void)
{
printf("Hello, C!\n");
/* void函数可以省略return */
}
/* 有参数无返回值的函数 */
void print_sum(int a, int b)
{
printf("%d + %d = %d\n", a, b, a + b);
}
/* 有参数有返回值的函数 */
int add(int a, int b)
{
return a + b; /* 返回计算结果 */
}
/* 无参数有返回值的函数 */
int get_input(void)
{
int num;
printf("请输入一个数字: ");
scanf("%d", &num);
return num;
}
int main(void)
{
/* 调用函数 */
say_hello(); /* 调用无参无返回值函数 */
print_sum(5, 3); /* 调用有参无返回值函数 */
int result = add(10, 20); /* 调用有参有返回值函数 */
printf("add(10, 20) = %d\n", result);
int num = get_input(); /* 调用无参有返回值函数 */
printf("你输入的数字是: %d\n", num);
return 0;
}函数声明
c
/*
* 函数声明(函数原型)
*/
#include <stdio.h>
/* 函数声明:告诉编译器函数的存在 */
int max(int a, int b); /* 函数原型 */
double average(int, int); /* 参数名可以省略 */
int main(void)
{
/* 在声明之后就可以调用函数 */
int m = max(10, 20);
printf("最大值: %d\n", m);
double avg = average(10, 20);
printf("平均值: %.2f\n", avg);
return 0;
}
/* 函数定义:在main函数之后 */
int max(int a, int b)
{
return (a > b) ? a : b;
}
double average(int a, int b)
{
return (a + b) / 2.0;
}参数传递
值传递
c
/*
* 值传递(传值)
*/
#include <stdio.h>
/* 尝试交换两个数(错误示例) */
void swap_wrong(int a, int b)
{
int temp = a;
a = b;
b = temp;
printf("函数内: a = %d, b = %d\n", a, b);
}
/* 正确的交换(使用指针) */
void swap_correct(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int main(void)
{
int x = 5, y = 10;
/* 值传递:函数内修改不影响原变量 */
printf("调用前: x = %d, y = %d\n", x, y);
swap_wrong(x, y);
printf("调用后: x = %d, y = %d\n", x, y); /* 值未改变 */
/* 指针传递:可以修改原变量 */
printf("\n使用指针:\n");
printf("调用前: x = %d, y = %d\n", x, y);
swap_correct(&x, &y);
printf("调用后: x = %d, y = %d\n", x, y); /* 值已交换 */
return 0;
}数组作为参数
c
/*
* 数组作为函数参数
*/
#include <stdio.h>
/* 数组参数会退化为指针 */
void print_array(int arr[], int len)
{
/* sizeof(arr) 是指针的大小,不是数组大小 */
for (int i = 0; i < len; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
/* 等价的写法 */
void print_array2(int *arr, int len)
{
for (int i = 0; i < len; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
/* 修改数组元素 */
void double_array(int arr[], int len)
{
for (int i = 0; i < len; i++) {
arr[i] *= 2; /* 修改会影响原数组 */
}
}
/* 计算数组元素和 */
int array_sum(int arr[], int len)
{
int sum = 0;
for (int i = 0; i < len; i++) {
sum += arr[i];
}
return sum;
}
/* 二维数组作为参数 */
void print_2d_array(int rows, int cols, int arr[rows][cols])
{
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main(void)
{
int arr[] = {1, 2, 3, 4, 5};
int len = sizeof(arr) / sizeof(arr[0]);
print_array(arr, len);
print_array2(arr, len);
double_array(arr, len);
printf("翻倍后: ");
print_array(arr, len);
int sum = array_sum(arr, len);
printf("数组元素和: %d\n", sum);
/* 二维数组 */
int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
printf("\n二维数组:\n");
print_2d_array(2, 3, matrix);
return 0;
}变量的作用域
c
/*
* 变量的作用域和生命周期
*/
#include <stdio.h>
/* 全局变量:在整个程序中可见 */
int global_var = 100;
/* 静态全局变量:只在当前文件可见 */
static int file_var = 200;
void func1(void)
{
/* 访问全局变量 */
printf("func1: global_var = %d\n", global_var);
/* 局部变量:只在函数内可见 */
int local_var = 10;
printf("func1: local_var = %d\n", local_var);
/* 静态局部变量:生命周期是整个程序 */
static int count = 0;
count++;
printf("func1: count = %d\n", count);
}
void func2(void)
{
/* 可以访问全局变量 */
printf("func2: global_var = %d\n", global_var);
/* 不能访问func1的局部变量 */
/* printf("%d", local_var); */ /* 错误 */
/* 同名的局部变量会隐藏全局变量 */
int global_var = 999;
printf("func2: local global_var = %d\n", global_var);
/* 使用::访问全局变量(C不支持,C++支持) */
/* printf("%d", ::global_var); */
}
/* 块作用域 */
void block_scope(void)
{
int x = 10;
printf("外层 x = %d\n", x);
{
int x = 20; /* 新的x,隐藏外层的x */
printf("内层 x = %d\n", x);
}
printf("外层 x = %d\n", x); /* 恢复外层的x */
}
int main(void)
{
printf("=== 全局变量 ===\n");
printf("main: global_var = %d\n", global_var);
printf("\n=== 局部变量 ===\n");
func1();
func1(); /* count会保持上次的值 */
printf("\n=== 同名变量 ===\n");
func2();
printf("\n=== 块作用域 ===\n");
block_scope();
return 0;
}递归函数
c
/*
* 递归函数
*/
#include <stdio.h>
/* 递归计算阶乘 */
long long factorial(int n)
{
/* 基准情况(终止条件) */
if (n <= 1) {
return 1;
}
/* 递归调用 */
return n * factorial(n - 1);
}
/* 递归计算斐波那契数列 */
long long fibonacci(int n)
{
if (n <= 0) return 0;
if (n == 1) return 1;
return fibonacci(n - 1) + fibonacci(n - 2);
}
/* 递归计算数字各位之和 */
int digit_sum(int n)
{
if (n < 10) {
return n;
}
return (n % 10) + digit_sum(n / 10);
}
/* 递归打印数字 */
void print_digits(int n)
{
if (n >= 10) {
print_digits(n / 10);
}
printf("%d ", n % 10);
}
/* 递归实现二分查找 */
int binary_search(int arr[], int left, int right, int target)
{
if (left > right) {
return -1; /* 未找到 */
}
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] > target) {
return binary_search(arr, left, mid - 1, target);
} else {
return binary_search(arr, mid + 1, right, target);
}
}
/* 汉诺塔问题 */
void hanoi(int n, char from, char to, char aux)
{
if (n == 1) {
printf("移动盘子1从%c到%c\n", from, to);
return;
}
hanoi(n - 1, from, aux, to);
printf("移动盘子%d从%c到%c\n", n, from, to);
hanoi(n - 1, aux, to, from);
}
int main(void)
{
/* 阶乘 */
printf("5! = %lld\n", factorial(5));
printf("10! = %lld\n", factorial(10));
/* 斐波那契 */
printf("\n斐波那契数列前10项:\n");
for (int i = 1; i <= 10; i++) {
printf("%lld ", fibonacci(i));
}
printf("\n");
/* 数字各位之和 */
printf("\n12345各位之和: %d\n", digit_sum(12345));
/* 打印数字各位 */
printf("12345各位数字: ");
print_digits(12345);
printf("\n");
/* 二分查找 */
int arr[] = {1, 3, 5, 7, 9, 11, 13, 15};
int len = sizeof(arr) / sizeof(arr[0]);
int target = 7;
int index = binary_search(arr, 0, len - 1, target);
printf("\n%d在数组中的索引: %d\n", target, index);
/* 汉诺塔 */
printf("\n3个盘子的汉诺塔:\n");
hanoi(3, 'A', 'C', 'B');
return 0;
}内联函数
c
/*
* 内联函数(C99)
*/
#include <stdio.h>
/* 内联函数:建议编译器内联展开 */
inline int square(int x)
{
return x * x;
}
/* 静态内联函数 */
static inline int cube(int x)
{
return x * x * x;
}
int main(void)
{
int a = 5;
/* 内联函数调用 */
printf("%d的平方: %d\n", a, square(a));
printf("%d的立方: %d\n", a, cube(a));
/* 内联函数适用于:
* 1. 函数体较小
* 2. 调用频繁
* 3. 执行时间短
*/
return 0;
}可变参数函数
c
/*
* 可变参数函数
*/
#include <stdio.h>
#include <stdarg.h> /* 可变参数相关宏 */
/* 计算多个整数的和 */
int sum(int count, ...)
{
va_list args; /* 声明可变参数列表 */
int total = 0;
va_start(args, count); /* 初始化args,count是最后一个固定参数 */
for (int i = 0; i < count; i++) {
total += va_arg(args, int); /* 获取下一个int类型的参数 */
}
va_end(args); /* 清理可变参数列表 */
return total;
}
/* 计算多个整数的平均值 */
double average(int count, ...)
{
va_list args;
double total = 0;
va_start(args, count);
for (int i = 0; i < count; i++) {
total += va_arg(args, int);
}
va_end(args);
return total / count;
}
/* 简化版printf */
void my_printf(const char *format, ...)
{
va_list args;
va_start(args, format);
while (*format) {
if (*format == '%') {
format++;
switch (*format) {
case 'd':
printf("%d", va_arg(args, int));
break;
case 'f':
printf("%f", va_arg(args, double));
break;
case 'c':
printf("%c", va_arg(args, int));
break;
case 's':
printf("%s", va_arg(args, char*));
break;
case '%':
putchar('%');
break;
default:
putchar(*format);
}
} else {
putchar(*format);
}
format++;
}
va_end(args);
}
int main(void)
{
/* 计算和 */
printf("sum(3, 1, 2, 3) = %d\n", sum(3, 1, 2, 3));
printf("sum(5, 1, 2, 3, 4, 5) = %d\n", sum(5, 1, 2, 3, 4, 5));
/* 计算平均值 */
printf("average(4, 1, 2, 3, 4) = %.2f\n", average(4, 1, 2, 3, 4));
/* 自定义printf */
printf("\n自定义printf:\n");
my_printf("整数: %d, 浮点: %f, 字符: %c, 字符串: %s\n",
42, 3.14, 'A', "Hello");
return 0;
}函数指针
c
/*
* 函数指针
*/
#include <stdio.h>
#include <stdlib.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 divide(int a, int b) { return b != 0 ? a / b : 0; }
/* 使用函数指针作为参数 */
int calculate(int a, int b, int (*operation)(int, int))
{
return operation(a, b);
}
/* 回调函数示例 */
void process_array(int arr[], int len, void (*process)(int*))
{
for (int i = 0; i < len; i++) {
process(&arr[i]);
}
}
void double_value(int *n) { *n *= 2; }
void square_value(int *n) { *n *= *n; }
/* 函数指针数组 */
int main(void)
{
/* 声明函数指针 */
int (*op)(int, int);
/* 指向add函数 */
op = add;
printf("add(10, 5) = %d\n", op(10, 5));
/* 指向subtract函数 */
op = subtract;
printf("subtract(10, 5) = %d\n", op(10, 5));
/* 使用函数指针作为参数 */
printf("\ncalculate(10, 5, add) = %d\n", calculate(10, 5, add));
printf("calculate(10, 5, multiply) = %d\n", calculate(10, 5, multiply));
/* 函数指针数组 */
int (*operations[])(int, int) = {add, subtract, multiply, divide};
char *op_names[] = {"加", "减", "乘", "除"};
printf("\n计算器:\n");
for (int i = 0; i < 4; i++) {
printf("10 %s 5 = %d\n", op_names[i], operations[i](10, 5));
}
/* 回调函数 */
int arr[] = {1, 2, 3, 4, 5};
int len = sizeof(arr) / sizeof(arr[0]);
printf("\n原数组: ");
for (int i = 0; i < len; i++) printf("%d ", arr[i]);
process_array(arr, len, double_value);
printf("\n翻倍后: ");
for (int i = 0; i < len; i++) printf("%d ", arr[i]);
process_array(arr, len, square_value);
printf("\n平方后: ");
for (int i = 0; i < len; i++) printf("%d ", arr[i]);
printf("\n");
return 0;
}小结
本章学习了:
- 函数定义:返回类型、函数名、参数列表、函数体
- 函数声明:函数原型,先声明后使用
- 参数传递:值传递、指针传递、数组传递
- 变量作用域:局部变量、全局变量、静态变量
- 递归函数:函数调用自身
- 内联函数:建议编译器内联展开
- 可变参数:va_list、va_start、va_arg、va_end
- 函数指针:指向函数的指针
下一章,我们将学习数组,了解C语言数组的定义和使用。
