
耕耘 :C、C++、嵌入式技术领域
✨**不要等待机会,而要创造机会!**✨
📽博主简介:
✨✨一位热爱生活的阳光大男孩.✨✨
前言
本文系统讲解C语言文件操作核心知识,涵盖文件概念、二进制与文本文件区别、流与文件指针机制,重点解析fopen、fclose函数使用及常见错误处理。通过实例演示文件顺序读写(如fputc),并强调打开文件后必须判断返回值、关闭文件时置空指针等最佳实践,为掌握文件操作提供完整技术框架。
文章目录
- 前言
-
- [1. 为什么使⽤⽂件?](#1. 为什么使⽤⽂件?)
- [2. 什么是⽂件?](#2. 什么是⽂件?)
- [2.1 程序⽂件](#2.1 程序⽂件)
- [2.2 数据⽂件](#2.2 数据⽂件)
- [2.3 ⽂件名](#2.3 ⽂件名)
- [3. ⼆进制⽂件和⽂本⽂件](#3. ⼆进制⽂件和⽂本⽂件)
- [4. ⽂件的打开和关闭](#4. ⽂件的打开和关闭)
-
- [4.1 流和标准流](#4.1 流和标准流)
-
- [4.1.1 流](#4.1.1 流)
- [4.1.2 标准流](#4.1.2 标准流)
- [4.2 ⽂件指针](#4.2 ⽂件指针)
- [4.3 ⽂件的打开和关闭](#4.3 ⽂件的打开和关闭)
-
- [4.3.1 fopen](#4.3.1 fopen)
- [4.3.2 fclose](#4.3.2 fclose)
- [5. ⽂件的顺序读写](#5. ⽂件的顺序读写)
-
- [5.1 fputc](#5.1 fputc)
- [5.2 fgetc](#5.2 fgetc)
- [5.3 feof和ferror](#5.3 feof和ferror)
- [5.4 fputs](#5.4 fputs)
- [5.5 fgets](#5.5 fgets)
- [5.6 fprintf](#5.6 fprintf)
- [5.7 fscanf](#5.7 fscanf)
- [5.8 fwrite](#5.8 fwrite)
- [5.9 fread](#5.9 fread)
- [5.10 对⽐⼀组函数:](#5.10 对⽐⼀组函数:)
-
- [5.10.1 sprintf](#5.10.1 sprintf)
- [5.10.2 sscanf](#5.10.2 sscanf)
- 结语
1. 为什么使⽤⽂件?
如果没有⽂件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失了,等再次运⾏程序,是看不到上次程序的数据的,如果要将数据进⾏持久化的保存,我们可以使⽤⽂件。
2. 什么是⽂件?
磁盘(硬盘)上的⽂件是⽂件。但是在程序设计中,我们⼀般谈的⽂件有两种:程序⽂件、数据⽂件(从⽂件功能的⻆度来分类的)。
2.1 程序⽂件
程序⽂件包括源程序⽂件(后缀为.c),⽬标⽂件(windows环境后缀为.obj),可执⾏程序(windows环境后缀为.exe)。
2.2 数据⽂件
⽂件的内容不⼀定是程序,⽽是程序运⾏时读写的数据,⽐如程序运⾏需要从中读取数据的⽂件,或者输出内容的⽂件。
本章讨论的是数据⽂件。
在以前各章所处理数据的输⼊输出都是以终端为对象的,即从终端的键盘输⼊数据,运⾏结果显⽰到显⽰器上。
其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使⽤,这⾥处理的就是磁盘上⽂件。
2.3 ⽂件名
⼀个⽂件要有⼀个唯⼀的⽂件标识,以便⽤⼾识别和引⽤。⽂件名包含3部分:⽂件路径+⽂件名主⼲+⽂件后缀
例如: c:\code\test.txt
为了⽅便起⻅,⽂件标识常被称为⽂件名。
3. ⼆进制⽂件和⽂本⽂件
根据数据的组织形式,数据⽂件被分为**⽂本⽂件和⼆进制⽂件** 。
数据在内存中以⼆进制的形式存储,如果不加转换的输出到外存的⽂件中,就是⼆进制⽂件。
如果要求在内存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的⽂件就是⽂本⽂件。
⼀个数据在⽂件中是怎么存储的呢?
字符⼀律以ASCII形式存储,数值型数据既可以⽤ASCII形式存储,也可以使⽤⼆进制形式存储。
如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占⽤5个字节(每个字符⼀个字节),⽽⼆进制形式输出,则在磁盘上只占4个字节。

4. ⽂件的打开和关闭
4.1 流和标准流
4.1.1 流
我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输⼊输出操作各不相同,为了⽅便程序员对各种设备进⾏⽅便的操作,我们抽象出了流的概念,我们可以把流想象成流淌着字符的河。C程序针对⽂件、画⾯、键盘等的数据输⼊输出操作都是通过流操作的。⼀般情况下,我们要想向流⾥写数据,或者从流中读取数据,都是要打开流,然后操作。
总结:流就是数据像水一样,持续、有序地流动,让程序能边接收边处理,而不是等全部准备好才开始。这在处理大文件、实时音视频、网络通信中特别重要。
4.1.2 标准流
那为什么我们从键盘输⼊数据,向屏幕上输出数据,并没有打开流呢?
那是因为C语⾔程序在启动的时候,默认打开了3个流:
• stdin - 标准输⼊流,在⼤多数的环境中从键盘输⼊,scanf函数就是从标准输⼊流中读取数据。
• stdout - 标准输出流,⼤多数的环境中输出⾄显⽰器界⾯,printf函数就是将信息输出到标准输出流中。
• stderr - 标准错误流,⼤多数环境中输出到显⽰器界⾯。
这是默认打开了这三个流,我们使⽤scanf、printf等函数就可以直接进⾏输⼊输出操作的。
stdin 、 stdout 、 stderr 三个流的类型是: FILE * ,通常称为⽂件指针。
*C语⾔中,就是通过 FILE 的⽂件指针来维护流的各种操作的。**
4.2 ⽂件指针
缓冲⽂件系统中,关键的概念是"⽂件类型指针",简称**"⽂件指针"**。每个被使⽤的⽂件都在内存中开辟了⼀个相应的⽂件信息区,⽤来存放⽂件的相关信息(如⽂件的名字,⽂件状态及⽂件当前的位置等)。这些信息是保存在⼀个结构体变量中的。该结构体类型是由系统声明的,取名 FILE 。
例如,VS2013 编译环境提供的 stdio.h 头⽂件中有以下的⽂件类型申明:
c
struct _iobuf
{
char* _ptr;
int _cnt;
char* _base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char* _tmpfname;
};
typedef struct _iobuf FILE;
不同的C编译器的FILE类型包含的内容不完全相同,但是⼤同⼩异。⼀般都是通过⼀个FILE的指针来维护这个FILE结构的变量,这样使⽤起来更加⽅便
下⾯我们可以创建⼀个FILE*的指针变量
c
FILE* pf;//⽂件指针变量
定义pf是⼀个指向FILE类型数据的指针变量。可以使pf指向某个⽂件的⽂件信息区(是⼀个结构体变量)。通过该⽂件信息区中的信息就能够访问该⽂件。也就是说,通过⽂件指针变量能够间接找到与它关联的⽂件 。

4.3 ⽂件的打开和关闭
⽂件在读写之前应该先打开⽂件,在使⽤结束之后应该关闭⽂件。
在编写程序的时候,在打开⽂件的同时,都会返回⼀个FILE*的指针变量指向该⽂件,也相当于建⽴了指针和⽂件的关系。
ANSI C 规定使⽤ fopen 函数来打开⽂件, fclose 来关闭⽂件。
4.3.1 fopen
c
//打开⽂件
FILE * fopen ( const char * filename, const char * mode );
功能: fopen 函数是⽤来打开参数 filename 指定的⽂件,同时将打开的⽂件和⼀个流进⾏关联,后续对流的操作是通过 fopen 函数返回的指针来维护。具体对流(关联的⽂件)的操作是通过参数mode 来指定的。
参数:
filename :表⽰被打开的⽂件的名字,这个名字可以绝对路径,也可以是相对路径。
mode :表⽰对打开的⽂件的操作⽅式,具体⻅下⾯的表格。
返回值:
• 若⽂件成功打开,该函数将返回⼀个指向 FILE 对象的指针,该指针可⽤于后续操作中标识对应的流。
• 若打开失败,则返回 NULL 指针,所以⼀定要对 fopen 的返回值做判断,来验证⽂件是否打开成功。
代码演⽰:
c
#include <stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "r"); //以"r"的形式打开⽂件,如果⽂件不存在,则打开失败
if (pf == NULL)
{
perror("fopen\n");
return 1;
}
printf("打开⽂件成功,可以对⽂件进⾏操作\n");
//不再使⽤⽂件时,需要关闭⽂件
return 0;
}
mode表⽰对打开的⽂件的操作⽅式:

4.3.2 fclose
c
//fclose函数原型
int fclose ( FILE * stream );
功能:关闭参数 stream 关联的⽂件,并取消其关联关系。与该流关联的所有内部缓冲区均会解除关
联并刷新:任何未写⼊的输出缓冲区内容将被写⼊,任何未读取的输⼊缓冲区内容将被丢弃。
参数:
stream :指向要关闭的流的 FILE 对象的指针
返回值:成功关闭 stream 指向的流会返回0,否则会返回 EOF 。
代码演⽰:
c
#include <stdio.h>
int main()
{
FILE* fp = fopen("test.txt", "r"); //以"r"的形式打开⽂件,如果⽂件不存在,则打开失败
if (fp == NULL)
{
perror("fopen\n");
return 1;
}
printf("打开⽂件成功,可以对⽂件进⾏操作\n");
//不再使⽤⽂件时,需要关闭⽂件
fclose(fp);
fp = NULL; //将指针置为NULL,避免成为野指针。
return 0;
}
5. ⽂件的顺序读写

上⾯说的适⽤于所有输⼊流⼀般指适⽤于标准输⼊流和其他输⼊流(如⽂件输⼊流);所有输出流⼀般指适⽤于标准输出流和其他输出流(如⽂件输出流)。
5.1 fputc
c
//fputc函数原型
int fputc ( int character, FILE * stream );
功能:将参数 character 指定的字符写⼊到 stream 指向的输出流中,通常⽤于向⽂件或标准输出流写⼊字符。在写⼊字符之后,还会调整指⽰器。字符会被写⼊流内部位置指⽰器当前指向的位置,随后该指⽰器⾃动向前移动⼀个位置。
参数:
character :被写⼊的字符
stream :是⼀个FILE*类型的指针,指向了输出流(通常是⽂件流或 stdout )。
返回值:
• 成功时返回写⼊的字符(以 int 形式)。
• 失败时返回 EOF (通常是 -1),错误指⽰器会被设置,可通过 ferror() 检查具体错误。
代码演⽰:
c
#include <stdio.h>
int main()
{
FILE* fp = fopen("test.txt", "w"); //以w的形式打开⽂件,才能正确的写⽂件
if (fp == NULL)
{
perror("fopen\n");
return 1;
}
fputc('a', fp);
fputc('b', fp);
fputc('c', fp);
//不再使⽤⽂件时,需要关闭⽂件
fclose(fp);
fp = NULL; //将指针置为NULL,避免成为野指针。
return 0;
}
//也可以循环写⼊多个字符的
#include <stdio.h>
int main()
{
FILE* fp = fopen("test.txt", "w"); //以w的形式打开⽂件,才能正确的写⽂件
if (fp == NULL)
{
perror("fopen\n");
return 1;
}
int ch = 0;
for (ch = 'a'; ch <= 'z'; ch++)
{
fputc(ch, fp);
}
//不再使⽤⽂件时,需要关闭⽂件
fclose(fp);
fp = NULL; //将指针置为NULL,避免成为野指针。
return 0;
}
5.2 fgetc
c
//fgetc函数的原型
int fgetc ( FILE * stream );
功能:从参数 stream 指向的流中读取⼀个字符。函数返回的是⽂件指⽰器当前指向的字符,读取这个字符之后,⽂件指⽰器⾃动前进到下⼀个字符。
参数:
stream : FILE*类型的⽂件指针,可以是 stdin ,也可以是其他输⼊流的指针。如果是 stdin 就从标准输⼊流读取数据。如果是⽂件流指针,就从⽂件读取数据。
返回值:
• 成功时返回读取的字符(以 int 形式)。
• 若调⽤时流已处于⽂件末尾,函数返回 EOF 并设置流的⽂件结束指⽰器( feof )。
若发⽣读取错误,函数返回 EOF 并设置流的错误指⽰器( ferror )。
代码演⽰:
c
#include <stdio.h>
int main()
{
FILE* fp = fopen("test.txt", "r");
if (fp == NULL)
{
perror("fopen\n");
return 1;
}
int i = 0;
for (i = 0; i < 10; i++)
{
int c = fgetc(fp);
fputc(c, stdout); //使⽤fputc在标准输出流上打印字符
}
//不再使⽤⽂件时,需要关闭⽂件
fclose(fp);
fp = NULL; //将指针置为NULL,避免成为野指针。
return 0;
}
5.3 feof和ferror
c
int feof ( FILE * stream );
//检测stream指针指向的流是否遇到⽂件末尾
int ferror ( FILE * stream );
//检测stream指针指向的流是否发⽣读/写错误
如果在读取⽂件的过程中,遇到了⽂件末尾,⽂件读取就会结束。这时读取函数会在对应的流上设置⼀个⽂件结束的指⽰符,这个⽂件结束指⽰符可以通过 feof 函数检测到。如果 feof 函数检测到⽂件结束指⽰符已经被设置,则返回⾮0的值,如果没有设置则返回0。
如果在读/写⽂件的过程中,发⽣了读/写错误,⽂件读取就会结束。这时读/写函数会在对应的流上设置⼀个错误指⽰符,这个错误指⽰符可以通过 ferror 函数检测到。如果 ferror 函数检测到错误指⽰符已经被设置,则返回⾮0的值,如果没有设置则返回0。
c
测试feof函数
#include <stdio.h>
//假设test.txt⽂件中存放abcdef
int main()
{
FILE* fp = fopen("test.txt", "r");
if (fp == NULL)
{
perror("fopen\n");
return 1;
}
int i = 0;
for (i = 0; i < 10; i++)
{
int c = fgetc(fp);
if (c == EOF)
{
if (feof(fp))
printf("遇到⽂件末尾了\n");
else if (ferror(fp))
printf("读取发⽣了错误\n");
}
else
{
fputc(c, stdout); //使⽤fputc在标准输出流上打印字符
}
}
//不再使⽤⽂件时,需要关闭⽂件
fclose(fp);
fp = NULL; //将指针置为NULL,避免成为野指针。
return 0;
}
c
测试ferror函数
#include <stdio.h>
//以写的形式打开⽂件后,再去读⽂件,就会发⽣错误
int main()
{
FILE* fp = fopen("test.txt", "w");
if (fp == NULL)
{
perror("fopen\n");
return 1;
}
int c = fgetc(fp);//读⽂件
if (c == EOF)
{
if (feof(fp))
printf("遇到⽂件末尾了\n");
else if (ferror(fp))
{
printf("读⽂件发⽣了错误\n");
}
}
else
{
fputc(c, stdout); //使⽤fputc在标准输出流上打印字符
}
//不再使⽤⽂件时,需要关闭⽂件
fclose(fp);
fp = NULL; //将指针置为NULL,避免成为野指针。
return 0;
}
5.4 fputs
c
fputs 函数原型
int fputs ( const char * str, FILE * stream );
功能:将参数 str 指向的字符串写⼊到参数 stream 指定的流中(不包含结尾的 \0 ),适⽤于⽂件流或标准输出(stdout)。
参数:
str : str是指针,指向了要写⼊的字符串(必须以 \0 结尾)
stream :是⼀个 FILE* 的指针,指向了要写⼊字符串的流。
返回值:
• 成功时返回⾮负整数。
• 失败时返回 EOF (-1),同时会设置流的错误指⽰器,可以使⽤ ferror() 检查错误原因。
代码演⽰:
c
#include <stdio.h>
int main()
{
FILE* fp = fopen("test.txt", "w");
if (fp == NULL)
{
perror("fopen\n");
return 1;
}
int i = 0;
fputs("abc\0def", fp);
fputs("hehe", fp);
//不再使⽤⽂件时,需要关闭⽂件
fclose(fp);
fp = NULL; //将指针置为NULL,避免成为野指针。
return 0;
}
5.5 fgets
c
fgets函数原型
char * fgets ( char * str, int num, FILE * stream );
功能:从 stream 指定输⼊流中读取字符串,⾄读取到换⾏符、⽂件末尾(EOF)或达到指定字符数(包含结尾的空字符 \0 ),然后将读取到的字符串存储到str指向的空间中。
参数:
• str :是指向字符数组的指针,str指向的空间⽤于存储读取到的字符串。
• num :最⼤读取字符数(包含结尾的 \0 ,实际最多读取 num-1 个字符)。
• stream :输⼊流的⽂件指针(如⽂件流或 stdin )。
返回值:
• 成功时返回 str 指针。
• 若在尝试读取字符时遇到⽂件末尾,则设置⽂件结束指⽰器,并返回 NULL ,需通过 feof()检测。
• 若发⽣读取错误,则设置流错误指⽰器,并返回 NULL,通过 ferror() 检测。
代码演⽰:
c
#include <stdio.h>
int main()
{
FILE* fp = fopen("test.txt", "r");//test.txt放的是123456789
if (fp == NULL)
{
perror("fopen\n");
return 1;
}
char arr1[] = "*************";
fgets(arr1, sizeof(arr1), fp);
char arr2[] = "*************";
fgets(arr2, sizeof(arr1), fp);
//不再使⽤⽂件时,需要关闭⽂件
fclose(fp);
fp = NULL; //将指针置为NULL,避免成为野指针。
return 0;
}
使⽤细节:
• 若读取到换⾏符( \n ),会将其包含在字符串中(除⾮超出 num-1 限制),然后以 \0 结尾。
• ⽂件末尾⽆换⾏符时,字符串以 \0 结尾,不包含 \n 。
5.6 fprintf
c
int fprintf ( FILE * stream, const char * format, ... );
//类⽐printf函数学习
功能: fprintf 是将格式化数据写⼊指定⽂件流的函数。它与 printf 类似,但可以输出到任意输出流(如磁盘⽂件、标准输出、标准错误等),⽽不仅限于控制台。
参数:
• stream :指向 FILE 对象的指针,表⽰要写⼊的⽂件流(如 stdout 、⽂件指针等)。
• format :格式化字符串,包含要写⼊的⽂本和格式说明符(如 %d 、 %s 等)。
• ... :可变参数列表,提供与格式字符串中说明符对应的数据。
返回值:
• 成功时,返回写⼊的字符总数(⾮负值)。
• 失败时,先设置对应流的错误指⽰器,再返回负值,可以通过 ferror() 来检测。
代码演⽰:
c
#include <stdio.h>
struct Stu
{
char name[30];
int age;
float score;
};
int main()
{
struct Stu b = { "zhangsan", 20, 85.5f };
FILE* fp = fopen("test.txt", "w");
if (fp == NULL)
{
perror("fopen\n");
return 1;
}
fprintf(fp, "%s %d %.1f", b.name, b.age, b.score);
//不再使⽤⽂件时,需要关闭⽂件
fclose(fp);
fp = NULL; //将指针置为NULL,避免成为野指针。
return 0;
}
5.7 fscanf
c
int fscanf ( FILE * stream, const char * format, ... );
//类⽐scanf函数来学习
功能: fscanf 是从指定⽂件流中读取格式化数据的函数。它类似于 scanf ,但可以指定输⼊源(如⽂件、标准输⼊等),⽽⾮仅限于控制台输⼊。适⽤于从⽂件解析结构化数据(如整数、浮点数、字符串等)。
参数:
• stream :指向 FILE 对象的指针,表⽰要读取的⽂件流(如 stdin 、⽂件指针等)。
• format :格式化字符串,定义如何解析输⼊数据(如 %d 、 %f 、 %s 等)。
• ... :可变参数列表,提供存储数据的变量地址(需与格式字符串中的说明符匹配)。
返回值:
• 成功时,函数返回成功填充到参数列表中的项数。该值可能与预期项数⼀致,也可能因以下原因少于预期(甚⾄为零):
◦ 格式和数据匹配失败;
◦ 读取发⽣错误;
◦ 到达⽂件末尾(EOF)。
• 如果在成功读取任何数据之前发⽣:
◦ 发⽣读取错误,会在对应流上设置错误指⽰符,则返回 EOF 。
◦ 到达⽂件末尾,会在对应流上设置⽂件结束指⽰符,则返回 EOF 。
代码演⽰:
假设在fprintf函数学习的时候,已经向⽂件中写⼊了数据: zhangsan 20 85.5 ,我们现在想在⽂件中读取这些数据出来。
c
#include <stdio.h>
struct Stu
{
char name[30];
int age;
float score;
};
int main()
{
struct Stu s = { 0 };
FILE* fp = fopen("test.txt", "r");
if (fp == NULL)
{
perror("fopen\n");
return 1;
}
fscanf(fp, "%s %d %f", s.name, &(s.age), &(s.score));//按照格式读取数据
fprintf(stdout, "%s %d %.1f\n", s.name, s.age, s.score);//打印数据在stdout上
//不再使⽤⽂件时,需要关闭⽂件
fclose(fp);
fp = NULL; //将指针置为NULL,避免成为野指针。
return 0;
}
5.8 fwrite
c
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
功能:函数⽤于将数据块写⼊ stream 指向的⽂件流中,是以2进制的形式写⼊的。
参数:
• ptr :指向要写⼊的数据块的指针。
• size :要写⼊的每个数据项的⼤⼩(以字节为单位)。
• count :要写⼊的数据项的数量。
• stream :指向 FILE 类型结构体的指针,指定了要写⼊数据的⽂件流。
返回值:返回实际写⼊的数据项数量。如果发⽣错误,则返回值可能⼩于 count 。
代码演⽰:
假设要将⼀组整数写⼊到⽂件 "data.bin" 中:
c
#include <stdio.h>
int main()
{
int data[] = { 1, 2, 3, 4, 5 };
// 打开⽂件
FILE* fp = fopen("data.bin", "wb");
// 检查⽂件是否成功打开
if (fp == NULL)
{
perror("fopen");
return 1;
}
// 将数据写⼊⽂件
if (fwrite(data, sizeof(int), 5, fp) != 5)
{
perror("fwrite");
return -1;
}
// 关闭⽂件
fclose(fp);
fp = NULL;
return 0;
}
5.9 fread
c
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
功能:函数⽤于从 stream 指向的⽂件流中读取数据块,并将其存储到 ptr 指向的内存缓冲区中。
参数:
• ptr :指向内存区域的指针,⽤于存储从⽂件中读取的数据。
• size :要读取的每个数据块的⼤⼩(以字节为单位)。
• count :要读取的数据块的数量。
• stream :指向 FILE 类型结构体的指针,指定了要从中读取数据的⽂件流。
返回值:返回实际读取的数据块数量。
使⽤注意事项:
• 需要包含 <stdio.h> 头⽂件。
• 在使⽤ fread() 之前,需要确保⽂件已经以⼆进制可读⽅式打开。
• ptr 指向的内存区域必须⾜够⼤,以便存储指定数量和⼤⼩的数据块。
• 如果 fread() 成功读取了指定数量的数据块,则返回值等于 count ;如果读取数量少于count ,则可能已经到达⽂件结尾或者发⽣了错误。
• 在⼆进制⽂件读取时, fread() 是常⽤的函数,但对于⽂本⽂件读取,通常使⽤ fgets()或 fscanf() 。
代码演⽰:
假设有⼀个⼆进制⽂件 "data.bin",包含⼀些整数数据,我们将使⽤ fread() 函数读取这些数据:
c
#include <stdio.h>
int main()
{
int data[5] = { 0 }; // 假设⽂件中包含 5 个整数数据
// 打开⽂件
FILE* fp = fopen("data.bin", "rb");
// 检查⽂件是否成功打开
if (fp == NULL) {
perror("fopen");
return -1;
}
// 从⽂件中读取整数数据块
size_t num_read = fread(data, sizeof(int), 5, fp);
// 检查读取是否成功
if (num_read != 5)
{
if (feof(fp))
printf("Reached end of file\n");
else if (ferror(fp))
printf("Error reading file\n");
}
else
{
// 输出读取的数据
for (int i = 0; i < 5; i++) {
printf("Data[%d]: %d\n", i, data[i]);
}
}
// 关闭⽂件
fclose(fp);
return 0;
}
5.10 对⽐⼀组函数:
scanf/fscanf/sscanf
printf/fprintf/sprintf
5.10.1 sprintf
c
int sprintf ( char * str, const char * format, ... );
功能:将格式化数据写⼊字符数组(字符串)。它类似于 printf ,但输出⽬标不是控制台或⽂件,⽽是⽤⼾指定的内存缓冲区。常⽤于动态⽣成字符串、拼接数据或转换数据格式。简⽽⾔之就是将格式化的数据转换成⼀个字符串。
参数:
• str :指向字符数组的指针,⽤于存储⽣成的字符串(需确保⾜够⼤以防⽌溢出)。
• format :格式化字符串,定义输出格式(如 %d 、 %f 、 %s 等)。
• ... :可变参数列表,提供与格式字符串中说明符对应的数据。
返回值:
• 成功时:返回写⼊ buffer 的字符数(不包括结尾的空字符 \0 )。
• 失败时:返回负值。
代码演⽰:
c
#include <stdio.h>
struct Stu
{
char name[30];
int age;
float score;
};
int main()
{
struct Stu s = { "zhangsan", 100, 85.5f };
//将s中的结构数据转换成⼀个字符串
char arr[100] = { 0 };
sprintf(arr, "%s %d %.1f", s.name, s.age, s.score);
printf("%s\n", arr);
return 0;
}
5.10.2 sscanf
c
int sscanf ( const char * str, const char * format, ...);
功能:从字符串中读取格式化数据。它与 scanf 类似,但输⼊源是内存中的字符串⽽⾮控制台或⽂件。常⽤于解析字符串中的结构化数据(如提取数字、分割⽂本等)。
参数:
• str :要解析的源字符串(输⼊数据来源)。
• format :格式化字符串,定义如何解析数据(如 %d 、 %f 、 %s 等)。
• ... :可变参数列表,提供存储数据的变量地址(需与格式字符串中的说明符匹配)
返回值:
• 成功时:返回成功解析并赋值的参数数量(⾮负值)。
• 失败或未匹配任何数据:若输⼊结束或解析失败,返回 EOF (通常是 -1 )。
代码演⽰:
c
#include <stdio.h>
struct Stu
{
char name[30];
int age;
float score;
};
int main()
{
char str[] = "zhangsan 100 85.5";
struct Stu s = { 0 };
//从str中的字符串内中解析出格式化的数据,存放在结构体中
sscanf(str, "%s %d %f", s.name, &(s.age), &(s.score));
//打印结构体s中的数据
printf("%s %d %.1f\n", s.name, s.age, s.score);
return 0;
}

结语
续.