C语言函数基础

函数是C语言程序的基本构建块,它将相关的代码组织在一起,实现特定的功能。函数可以接收输入参数,执行特定的操作,并返回结果。使用函数可以提高代码的可读性、可维护性和可重用性。本文将详细介绍C语言函数的定义、调用、参数传递和各种应用场景。

函数的基本概念

什么是函数

函数是一段具有特定功能的代码块,它可以:

  • 接收输入参数(可选)
  • 执行特定的操作
  • 返回结果(可选)
  • 被多次调用和重用

函数的优势

  1. 代码重用:避免重复编写相同的代码
  2. 模块化:将复杂问题分解为小的、可管理的部分
  3. 易于维护:修改功能时只需修改函数内部
  4. 易于测试:可以单独测试每个函数
  5. 提高可读性:使程序结构更清晰

函数的定义

基本语法

1
2
3
4
返回类型 函数名(参数列表) {
// 函数体
return 返回值; // 可选
}

简单函数示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <stdio.h>

// 无参数无返回值的函数
void say_hello() {
printf("Hello, World!\n");
}

// 有参数无返回值的函数
void greet(char name[]) {
printf("Hello, %s!\n", name);
}

// 有参数有返回值的函数
int add(int a, int b) {
return a + b;
}

// 无参数有返回值的函数
int get_random_number() {
return 42; // 简单示例
}

int main() {
say_hello();
greet("Alice");

int result = add(5, 3);
printf("5 + 3 = %d\n", result);

int random = get_random_number();
printf("随机数:%d\n", random);

return 0;
}

函数的声明和定义

函数声明(原型)

函数声明告诉编译器函数的名称、返回类型和参数类型,但不包含函数体。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <stdio.h>

// 函数声明
int multiply(int x, int y);
float calculate_area(float radius);
void print_menu();

int main() {
// 可以在定义之前调用函数
int result = multiply(4, 5);
printf("4 × 5 = %d\n", result);

float area = calculate_area(3.0);
printf("半径为3的圆面积:%.2f\n", area);

print_menu();

return 0;
}

// 函数定义
int multiply(int x, int y) {
return x * y;
}

float calculate_area(float radius) {
const float PI = 3.14159;
return PI * radius * radius;
}

void print_menu() {
printf("=== 主菜单 ===\n");
printf("1. 选项一\n");
printf("2. 选项二\n");
printf("3. 退出\n");
}

参数传递

值传递(Pass by Value)

C语言默认使用值传递,函数接收参数的副本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>

void modify_value(int x) {
printf("函数内部,修改前:x = %d\n", x);
x = 100;
printf("函数内部,修改后:x = %d\n", x);
}

int main() {
int num = 10;
printf("调用前:num = %d\n", num);

modify_value(num);

printf("调用后:num = %d\n", num); // num仍然是10

return 0;
}

指针传递(模拟引用传递)

通过传递指针可以修改原始变量的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <stdio.h>

void swap_values(int *a, int *b) {
printf("交换前:*a = %d, *b = %d\n", *a, *b);
int temp = *a;
*a = *b;
*b = temp;
printf("交换后:*a = %d, *b = %d\n", *a, *b);
}

void modify_value_by_pointer(int *x) {
printf("函数内部,修改前:*x = %d\n", *x);
*x = 100;
printf("函数内部,修改后:*x = %d\n", *x);
}

int main() {
int num1 = 10, num2 = 20;
printf("交换前:num1 = %d, num2 = %d\n", num1, num2);

swap_values(&num1, &num2);

printf("交换后:num1 = %d, num2 = %d\n", num1, num2);

printf("\n修改测试:\n");
int num = 10;
printf("调用前:num = %d\n", num);

modify_value_by_pointer(&num);

printf("调用后:num = %d\n", num); // num变成了100

return 0;
}

返回值

不同类型的返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <stdio.h>

// 返回整数
int factorial(int n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}

// 返回浮点数
float celsius_to_fahrenheit(float celsius) {
return (celsius * 9.0 / 5.0) + 32.0;
}

// 返回字符
char get_grade(int score) {
if (score >= 90) return 'A';
else if (score >= 80) return 'B';
else if (score >= 70) return 'C';
else if (score >= 60) return 'D';
else return 'F';
}

// 返回布尔值(用int表示)
int is_even(int number) {
return (number % 2 == 0);
}

int main() {
// 测试各种返回值类型
printf("5的阶乘:%d\n", factorial(5));

float temp_f = celsius_to_fahrenheit(25.0);
printf("25°C = %.1f°F\n", temp_f);

char grade = get_grade(85);
printf("85分的等级:%c\n", grade);

int number = 8;
printf("%d是%s数\n", number, is_even(number) ? "偶" : "奇");

return 0;
}

多个返回值(通过指针)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>

// 通过指针参数返回多个值
void calculate_circle(float radius, float *area, float *circumference) {
const float PI = 3.14159;
*area = PI * radius * radius;
*circumference = 2 * PI * radius;
}

// 返回除法的商和余数
void divide_with_remainder(int dividend, int divisor, int *quotient, int *remainder) {
*quotient = dividend / divisor;
*remainder = dividend % divisor;
}

int main() {
float radius = 5.0;
float area, circumference;

calculate_circle(radius, &area, &circumference);
printf("半径%.1f的圆:\n", radius);
printf("面积:%.2f\n", area);
printf("周长:%.2f\n", circumference);

int dividend = 17, divisor = 5;
int quotient, remainder;

divide_with_remainder(dividend, divisor, &quotient, &remainder);
printf("\n%d ÷ %d = %d 余 %d\n", dividend, divisor, quotient, remainder);

return 0;
}

局部变量和全局变量

变量作用域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <stdio.h>

// 全局变量
int global_counter = 0;
const float PI = 3.14159; // 全局常量

void increment_global() {
global_counter++;
printf("全局计数器:%d\n", global_counter);
}

void local_variable_demo() {
int local_var = 10; // 局部变量
printf("局部变量:%d\n", local_var);

// 局部变量可以与全局变量同名
int global_counter = 999;
printf("局部的global_counter:%d\n", global_counter);
}

void static_variable_demo() {
static int static_var = 0; // 静态局部变量
static_var++;
printf("静态变量:%d\n", static_var);
}

int main() {
printf("初始全局计数器:%d\n", global_counter);

increment_global();
increment_global();

local_variable_demo();
printf("调用后全局计数器:%d\n", global_counter);

// 测试静态变量
printf("\n静态变量测试:\n");
static_variable_demo(); // 输出1
static_variable_demo(); // 输出2
static_variable_demo(); // 输出3

return 0;
}

递归函数

递归是函数调用自身的编程技术。

基本递归示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <stdio.h>

// 计算阶乘
int factorial(int n) {
// 基础情况
if (n <= 1) {
return 1;
}
// 递归情况
return n * factorial(n - 1);
}

// 计算斐波那契数列
int fibonacci(int n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}

// 计算最大公约数(欧几里得算法)
int gcd(int a, int b) {
if (b == 0) {
return a;
}
return gcd(b, a % b);
}

// 计算数字的位数
int count_digits(int n) {
if (n == 0) {
return 1;
}
if (n < 10) {
return 1;
}
return 1 + count_digits(n / 10);
}

int main() {
// 测试阶乘
printf("阶乘测试:\n");
for (int i = 0; i <= 5; i++) {
printf("%d! = %d\n", i, factorial(i));
}

// 测试斐波那契数列
printf("\n斐波那契数列前10项:\n");
for (int i = 0; i < 10; i++) {
printf("%d ", fibonacci(i));
}
printf("\n");

// 测试最大公约数
printf("\ngcd(48, 18) = %d\n", gcd(48, 18));
printf("gcd(100, 25) = %d\n", gcd(100, 25));

// 测试位数计算
printf("\n位数计算:\n");
printf("12345有%d位\n", count_digits(12345));
printf("0有%d位\n", count_digits(0));

return 0;
}

递归的注意事项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <stdio.h>

// 错误的递归:没有基础情况
/*
int bad_recursion(int n) {
return bad_recursion(n - 1); // 会导致栈溢出
}
*/

// 改进的递归:带有深度限制
int safe_recursion(int n, int depth) {
if (depth > 1000) { // 防止栈溢出
printf("递归深度过大,停止递归\n");
return -1;
}

if (n <= 0) {
return 0;
}

return n + safe_recursion(n - 1, depth + 1);
}

// 尾递归优化示例
int factorial_tail_recursive(int n, int accumulator) {
if (n <= 1) {
return accumulator;
}
return factorial_tail_recursive(n - 1, n * accumulator);
}

int factorial_optimized(int n) {
return factorial_tail_recursive(n, 1);
}

int main() {
printf("安全递归测试:\n");
int result = safe_recursion(10, 0);
printf("1到10的和:%d\n", result);

printf("\n尾递归优化测试:\n");
printf("5! = %d\n", factorial_optimized(5));

return 0;
}

函数指针

函数指针允许将函数作为参数传递或存储在变量中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#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 calculate(int a, int b, int (*operation)(int, int)) {
return operation(a, b);
}

// 函数指针数组示例
void print_menu() {
printf("1. 加法\n");
printf("2. 减法\n");
printf("3. 乘法\n");
}

int main() {
// 声明函数指针
int (*func_ptr)(int, int);

// 函数指针指向不同的函数
func_ptr = add;
printf("使用函数指针调用加法:5 + 3 = %d\n", func_ptr(5, 3));

func_ptr = multiply;
printf("使用函数指针调用乘法:5 × 3 = %d\n", func_ptr(5, 3));

// 使用函数指针作为参数
printf("\n使用函数作为参数:\n");
printf("10 + 5 = %d\n", calculate(10, 5, add));
printf("10 - 5 = %d\n", calculate(10, 5, subtract));
printf("10 × 5 = %d\n", calculate(10, 5, multiply));

// 函数指针数组
int (*operations[])(int, int) = {add, subtract, multiply};
char *op_names[] = {"加法", "减法", "乘法"};

printf("\n使用函数指针数组:\n");
for (int i = 0; i < 3; i++) {
printf("%s:8 和 3 = %d\n", op_names[i], operations[i](8, 3));
}

return 0;
}

实际应用示例

示例1:数学工具库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <stdio.h>
#include <math.h>

// 数学工具函数
int is_prime(int n) {
if (n <= 1) return 0;
if (n <= 3) return 1;
if (n % 2 == 0 || n % 3 == 0) return 0;

for (int i = 5; i * i <= n; i += 6) {
if (n % i == 0 || n % (i + 2) == 0) {
return 0;
}
}
return 1;
}

int power(int base, int exponent) {
if (exponent == 0) return 1;
if (exponent == 1) return base;

int result = 1;
for (int i = 0; i < exponent; i++) {
result *= base;
}
return result;
}

float average(int numbers[], int count) {
if (count == 0) return 0.0;

int sum = 0;
for (int i = 0; i < count; i++) {
sum += numbers[i];
}
return (float)sum / count;
}

int find_max(int numbers[], int count) {
if (count == 0) return 0;

int max = numbers[0];
for (int i = 1; i < count; i++) {
if (numbers[i] > max) {
max = numbers[i];
}
}
return max;
}

int find_min(int numbers[], int count) {
if (count == 0) return 0;

int min = numbers[0];
for (int i = 1; i < count; i++) {
if (numbers[i] < min) {
min = numbers[i];
}
}
return min;
}

int main() {
// 测试素数判断
printf("素数测试:\n");
for (int i = 2; i <= 20; i++) {
if (is_prime(i)) {
printf("%d ", i);
}
}
printf("\n");

// 测试幂运算
printf("\n幂运算测试:\n");
printf("2^3 = %d\n", power(2, 3));
printf("5^4 = %d\n", power(5, 4));

// 测试数组统计函数
int numbers[] = {10, 5, 8, 3, 15, 7, 12};
int count = sizeof(numbers) / sizeof(numbers[0]);

printf("\n数组统计:\n");
printf("数组:");
for (int i = 0; i < count; i++) {
printf("%d ", numbers[i]);
}
printf("\n");

printf("平均值:%.2f\n", average(numbers, count));
printf("最大值:%d\n", find_max(numbers, count));
printf("最小值:%d\n", find_min(numbers, count));

return 0;
}

示例2:学生成绩管理系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#include <stdio.h>
#include <string.h>

#define MAX_STUDENTS 100
#define NAME_LENGTH 50

// 学生结构体
typedef struct {
char name[NAME_LENGTH];
int id;
float score;
char grade;
} Student;

// 函数声明
void input_student(Student *student);
void calculate_grade(Student *student);
void print_student(const Student *student);
float calculate_class_average(const Student students[], int count);
void find_top_student(const Student students[], int count, Student *top);
int count_passing_students(const Student students[], int count);
void print_statistics(const Student students[], int count);

int main() {
Student students[MAX_STUDENTS];
int student_count = 0;
int choice;

printf("学生成绩管理系统\n");

do {
printf("\n=== 主菜单 ===\n");
printf("1. 添加学生\n");
printf("2. 显示所有学生\n");
printf("3. 显示统计信息\n");
printf("0. 退出\n");
printf("请选择:");
scanf("%d", &choice);

switch (choice) {
case 1:
if (student_count < MAX_STUDENTS) {
input_student(&students[student_count]);
calculate_grade(&students[student_count]);
student_count++;
printf("学生添加成功!\n");
} else {
printf("学生数量已达上限!\n");
}
break;
case 2:
if (student_count == 0) {
printf("暂无学生记录\n");
} else {
printf("\n所有学生信息:\n");
for (int i = 0; i < student_count; i++) {
print_student(&students[i]);
}
}
break;
case 3:
if (student_count == 0) {
printf("暂无学生记录\n");
} else {
print_statistics(students, student_count);
}
break;
case 0:
printf("谢谢使用!\n");
break;
default:
printf("无效选择!\n");
break;
}
} while (choice != 0);

return 0;
}

// 函数定义
void input_student(Student *student) {
printf("请输入学生姓名:");
scanf("%s", student->name);
printf("请输入学号:");
scanf("%d", &student->id);
printf("请输入成绩:");
scanf("%f", &student->score);
}

void calculate_grade(Student *student) {
if (student->score >= 90) {
student->grade = 'A';
} else if (student->score >= 80) {
student->grade = 'B';
} else if (student->score >= 70) {
student->grade = 'C';
} else if (student->score >= 60) {
student->grade = 'D';
} else {
student->grade = 'F';
}
}

void print_student(const Student *student) {
printf("姓名:%-10s 学号:%-8d 成绩:%6.1f 等级:%c\n",
student->name, student->id, student->score, student->grade);
}

float calculate_class_average(const Student students[], int count) {
if (count == 0) return 0.0;

float sum = 0.0;
for (int i = 0; i < count; i++) {
sum += students[i].score;
}
return sum / count;
}

void find_top_student(const Student students[], int count, Student *top) {
if (count == 0) return;

*top = students[0];
for (int i = 1; i < count; i++) {
if (students[i].score > top->score) {
*top = students[i];
}
}
}

int count_passing_students(const Student students[], int count) {
int passing = 0;
for (int i = 0; i < count; i++) {
if (students[i].score >= 60) {
passing++;
}
}
return passing;
}

void print_statistics(const Student students[], int count) {
printf("\n=== 班级统计信息 ===\n");
printf("总学生数:%d\n", count);

float average = calculate_class_average(students, count);
printf("平均成绩:%.2f\n", average);

Student top_student;
find_top_student(students, count, &top_student);
printf("最高分学生:%s (%.1f分)\n", top_student.name, top_student.score);

int passing = count_passing_students(students, count);
printf("及格人数:%d\n", passing);
printf("及格率:%.1f%%\n", (float)passing / count * 100);
}

常见错误和注意事项

1. 函数声明和定义不匹配

1
2
3
4
5
6
// 错误:声明和定义的参数类型不匹配
int add(int a, int b); // 声明

float add(float a, float b) { // 错误:返回类型不匹配
return a + b;
}

2. 忘记返回值

1
2
3
4
5
6
7
8
9
10
11
// 错误:声明有返回值但没有返回
int calculate_sum(int a, int b) {
int sum = a + b;
// 忘记return语句
}

// 正确:
int calculate_sum(int a, int b) {
int sum = a + b;
return sum;
}

3. 参数传递错误

1
2
3
4
5
6
7
8
9
// 错误:想要修改原变量但使用了值传递
void increment(int x) {
x++; // 只修改了副本
}

// 正确:使用指针
void increment(int *x) {
(*x)++;
}

总结

函数是C语言编程的核心概念,通过本文的学习,你应该掌握:

  1. 函数定义:语法结构和基本概念
  2. 函数声明:原型声明的重要性
  3. 参数传递:值传递和指针传递的区别
  4. 返回值:不同类型返回值的处理
  5. 变量作用域:局部变量、全局变量和静态变量
  6. 递归函数:递归的原理和应用
  7. 函数指针:高级函数使用技巧

在实际编程中,要注意:

  • 合理设计函数的功能和接口
  • 选择合适的参数传递方式
  • 处理好函数的返回值
  • 避免常见的语法错误
  • 编写可读性强、可维护的函数

掌握函数的使用将大大提高你的编程能力,为编写复杂程序和学习高级编程概念打下坚实的基础。

版权所有,如有侵权请联系我