第一部分:函数
函数是 C 语言程序的基本构建块,它是一段可以重复使用的代码,用于执行特定的任务,使用函数可以带来以下好处:

(图片来源网络,侵删)
- 代码重用:避免编写重复的代码。
- 模块化:将复杂的问题分解为小的、易于管理的部分。
- 可读性:使代码结构更清晰,易于理解和维护。
- 易于调试:可以单独测试和调试每个函数。
函数的基本结构
一个完整的函数定义包含以下几个部分:
返回类型 函数名(参数列表) {
// 函数体
// 执行的代码
return 返回值; // 如果返回类型不是 void
}
- 返回类型:函数执行完毕后返回给调用者的数据的类型,如果函数不返回任何值,则使用
void。 - 函数名:给函数起的名称,用于调用。
- 参数列表:传递给函数的变量的列表,多个参数用逗号隔开,如果函数不接受任何参数,可以使用
void或者留空(在 C99 标准之后,留空 表示无参数)。 - 函数体:包含在一对花括号 中的代码,是函数实际执行的部分。
- return 语句:用于从函数返回一个值,并终止函数的执行,如果返回类型是
void,return语句可以省略,或者只写return;。
函数的示例
示例 1:无参数,无返回值
#include <stdio.h>
// 函数声明
void printWelcomeMessage();
int main() {
printWelcomeMessage(); // 函数调用
return 0;
}
// 函数定义
void printWelcomeMessage() {
printf("欢迎来到 C 语言世界!\n");
}
示例 2:有参数,有返回值
#include <stdio.h>
// 函数声明
int add(int a, int b);
int main() {
int num1 = 5;
int num2 = 10;
int sum;
sum = add(num1, num2); // 函数调用,并接收返回值
printf("和为: %d\n", sum);
return 0;
}
// 函数定义
int add(int a, int b) {
return a + b; // 返回 a 和 b 的和
}
第二部分:文件指针
在 C 语言中,对文件的所有操作都是通过文件指针来完成的,文件指针是一个指向 FILE 结构体的指针,该结构体包含了文件操作所需的所有信息(如文件名、状态、当前位置等)。

(图片来源网络,侵删)
FILE 和 fopen
FILE:这是一个在<stdio.h>中定义的结构体类型,你不需要关心它的具体内部结构,只需要知道它代表了文件流。fopen():这是一个标准库函数,用于打开文件,并返回一个指向该文件的FILE指针。
FILE *fopen(const char *filename, const char *mode);
filename:要打开的文件名(可以包含路径)。mode:文件打开模式,决定了你如何使用这个文件。
| 模式 | 含义 | 如果文件不存在 | 如果文件存在 |
|---|---|---|---|
"r" |
只读 | 报错 | 打开成功 |
"w" |
只写 | 创建新文件 | 清空文件内容 |
"a" |
追加 | 创建新文件 | 在文件末尾写入 |
"r+" |
读写 | 报错 | 打开成功,指针在开头 |
"w+" |
读写 | 创建新文件 | 清空文件内容 |
"a+" |
读写 | 创建新文件 | 打开成功,指针在末尾 |
重要:fopen 可能会因为文件无法打开(如路径错误、权限不足等)而失败,此时它会返回 NULL,在每次使用 fopen 后,必须检查返回值是否为 NULL。
文件操作常用函数
一旦你通过 fopen 获得了文件指针,就可以使用一系列函数来操作文件。
| 函数 | 功能 |
|---|---|
fprintf(fp, "...", ...) |
格式化写入数据到文件 |
fscanf(fp, "...", ...) |
从文件格式化读取数据 |
fputc(c, fp) |
写入一个字符到文件 |
fgetc(fp) |
从文件读取一个字符 |
fputs(s, fp) |
写入一个字符串到文件 |
fgets(s, n, fp) |
从文件读取一行字符串 |
fseek(fp, offset, origin) |
移动文件指针到指定位置 |
ftell(fp) |
获取当前文件指针的位置 |
rewind(fp) |
将文件指针重置到文件开头 |
fwrite(buffer, size, count, fp) |
以二进制形式写入一块数据 |
fread(buffer, size, count, fp) |
以二进制形式读取一块数据 |
fclose(fp) |
关闭文件 |
文件操作完整示例
下面是一个完整的示例,演示了如何创建、写入、读取和关闭文件。
#include <stdio.h>
#include <string.h> // 使用 strcpy 函数
int main() {
// 1. 定义文件指针
FILE *fp;
char filename[] = "my_data.txt";
char content[100] = "这是要写入文件的第一行内容,\n";
char read_content[100];
// 2. 以写模式 ("w") 打开文件
// 注意:一定要检查 fopen 是否成功!
fp = fopen(filename, "w");
if (fp == NULL) {
printf("无法打开文件 %s\n", filename);
return 1; // 返回非零值表示程序出错
}
// 3. 写入数据到文件
fprintf(fp, "%s", content);
fputs("这是用 fputs 写入的第二行,\n", fp);
printf("数据已成功写入 %s\n", filename);
// 4. 关闭文件
fclose(fp);
// --- 接下来是读取文件部分 ---
// 5. 以读模式 ("r") 打开文件
fp = fopen(filename, "r");
if (fp == NULL) {
printf("无法打开文件 %s 进行读取\n", filename);
return 1;
}
// 6. 从文件读取数据
printf("\n--- 开始读取文件内容 ---\n");
// 使用 fgets 读取一行
if (fgets(read_content, sizeof(read_content), fp) != NULL) {
printf("读取到第一行: %s", read_content);
}
// 使用 fscanf 读取
// 注意:fscanf 遇到空格会停止,所以不适合读取包含空格的行
// 这里我们假设下一行是简单的数字和字符串
fprintf(fp, "用户ID: 1001\n"); // 先写入一些结构化数据以便演示
rewind(fp); // 重置指针到文件开头
int id;
char name[50];
if (fscanf(fp, "用户ID: %d\n", &id) == 1) {
printf("读取到用户ID: %d\n", id);
}
// 重置指针到文件开头,以便读取完整内容
rewind(fp);
printf("\n--- 文件完整内容 ---\n");
while (fgets(read_content, sizeof(read_content), fp) != NULL) {
printf("%s", read_content);
}
// 7. 关闭文件
fclose(fp);
return 0;
}
错误处理:perror 和 errno
当文件操作失败时,fopen 等函数会返回 NULL,为了了解具体的错误原因,可以使用 perror 函数。

(图片来源网络,侵删)
fp = fopen("non_existent_file.txt", "r");
if (fp == NULL) {
// perror 会打印你提供的字符串,然后加上一个冒号和系统错误信息
perror("打开文件失败");
// 可能的输出: "打开文件失败: No such file or directory"
return 1;
}
第三部分:函数与文件指针的结合
在实际编程中,我们经常将文件操作封装成独立的函数,以提高代码的模块化和复用性。
示例:一个简单的日志记录函数
#include <stdio.h>
#include <time.h>
#include <string.h>
// 函数声明
void log_message(const char *filename, const char *message);
int main() {
log_message("app.log", "程序启动成功。");
log_message("app.log", "用户登录。");
log_message("app.log", "程序准备退出。");
return 0;
}
// 函数定义:向日志文件追加一条记录
void log_message(const char *filename, const char *message) {
FILE *fp = fopen(filename, "a"); // 使用 "a" 模式进行追加
if (fp == NULL) {
perror("无法打开日志文件");
return; // 如果打不开文件,函数直接返回
}
// 获取当前时间
time_t now;
time(&now);
char *time_str = ctime(&now);
time_str[strlen(time_str) - 1] = '\0'; // 去掉 ctime 添加的换行符
// 写入日志内容
fprintf(fp, "[%s] %s\n", time_str, message);
// 关闭文件
fclose(fp);
}
这个例子中,log_message 函数专门负责处理日志写入。main 函数只需要调用它,而不需要关心文件是如何打开和关闭的,这使得代码非常清晰。
| 概念 | 关键点 |
|---|---|
| 函数 | 是可重用的代码块,有返回类型、函数名、参数列表和函数体,用于模块化编程。 |
| 文件指针 | 是一个指向 FILE 结构体的指针,是所有文件操作的入口。 |
fopen |
用于打开文件,必须检查其返回值是否为 NULL。 |
| 文件操作 | 使用 fprintf, fscanf, fgets, fputs 等函数进行读写。 |
fclose |
非常重要!操作完成后必须关闭文件,释放资源。 |
| 结合使用 | 将文件操作封装在函数中,是编写健壮、可维护 C 程序的良好实践。 |
