这篇文章将总结c语言中一系列关于结构体的知识点。
如果您对这篇文章内容感到满意,可以点进我的主页查看更多相关内容。
我的主页:OMGmyhair的优快云博客主页
一、 流
二、文件指针
三、标准流
文件指针 | 流 | 默认的含义 |
stdin | 标准输入 | 键盘 |
stdout | 标准输出 | 屏幕 |
stderr | 标准误差 | 屏幕 |
四、文件操作函数
1.fopen函数

2.fclose函数

<模式>
字符串 | 含义 |
"r" | 打开文件用于读 |
"w" | 打开文件用于写(文件不需要存在) |
"wx" | 创建文件用于写(文件不能已经存在)* |
"w+x" | 创建文件用于更新(文件不能已经存在)* |
"a" | 打开文件用于追加(文件不需要存在) |
"r+" | 打开文件用于读和写,从文件头开始 |
"w+" | 打开文件用于读和写(如果文件存在就截去) |
"a+" | 打开文件用于读和写(如果文件存在就追加) |
用于二进制文件的模式字符串
字符串 | 含义 |
"rb" | 打开文件用于读 |
"wb" | 打开文件用于写(文件不需要存在) |
"wbx" | 创建文件用于写(文件不能已经存在)* |
"ab" | 打开文件用于追加(文件不需要存在) |
"r+b"或"rb+" | 打开文件用于读和写,从文件头开始 |
"w+b"或"wb+" | 打开文件用于读和写(如果文件存在就截去) |
"w+bx"或"wb+x" | 创建文件用于更新(文件不能已经存在)* |
"a+b"或"ab+" | 打开文件用于读和写(如果文件存在就追加) |
3.顺序读写函数
函数名 | 功能 | 适用于 |
fgetc | 字符输入函数 | 所有输入流 |
fputc | 字符输出函数 | 所有输出流 |
fgets | 文本行输入函数 | 所有输入流 |
fputs | 文本行输出函数 | 所有输出流 |
fscanf | 格式化输入函数 | 所有输入流 |
fprintf | 格式化输出函数 | 所有输出流 |
fread | 二进制输入 | 文件 |
fwrite | 二进制输出 | 文件 |
(1)fprintf函数
你可能会觉得这个函数跟printf函数长得很像,我们来看一看它的定义:
我们可以用这个函数进行格式化的输出,从上面的表格我们可以看出,它针对的是所有输出流,这里我们不仅能将数据输出到文件中去,还能将其输出到屏幕上,我们照样用两个实例来加深理解:
首先输出到文件中去:
int main()
{
FILE* pf = fopen("text.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int a = 0;
for (int i = 0; i < 10; i++)
{
fprintf(pf,"%d", i);
}
fclose(pf);
pf = NULL;
return 0;
}
此处我们将0~9个数字都输出到文件:
现在我们再试试输出至屏幕上(这里我们需要用到文件指针stdout,它维护的是标准输出流):
int main()
{
FILE* pf = fopen("text.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int a = 0;
for (int i = 0; i < 10; i++)
{
fprintf(stdout, "%d", i);
}
fclose(pf);
pf = NULL;
return 0;
}
(2)fscanf
我们来看看fscanf函数的定义
可以看到这个函数的功能是从流中拿取格式化的数据,跟fprintf类似,这个函数也可以从屏幕上读取数据,或者从文件中读取数据,我们举两个实例:
从文件中读取数据:
int main()
{
FILE* pf = fopen("text.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int a ;
for (int i = 0; i < 10; i++)
{
fscanf(pf, "%d", &a);
}
printf("%d", a);
fclose(pf);
pf = NULL;
return 0;
}
注意在用fscanf的时候,要注意&符号的使用。
我们再试试让其从屏幕上读取数据
int main()
{
FILE* pf = fopen("text.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int a ;
fscanf(stdin, "%d", &a);
printf("%d", a);
fclose(pf);
pf = NULL;
return 0;
}
那我们是否可以从屏幕输入数据到文件呢?让我们来试试
int main()
{
FILE* pf = fopen("text.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int arr[10] = { 0 };
for (int i = 0; i < 10; i++)
{
fscanf(stdin, "%d", &arr[i]);
}
for (int i = 0; i < 10; i++)
{
fprintf(pf, "%d", arr[i]);
}
fclose(pf);
pf = NULL;
return 0;
}
这里我们向屏幕输入9876543210
查看文件:
要注意不能直接像下面一样写:
需要注意的是fscanf函数不能用于两个流之间
int main()
{
FILE* pf = fopen("text.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fscanf(stdin, "%d", pf);
fclose(pf);
pf = NULL;
return 0;
}
(3)fputc
我们来看看fputc函数的定义
我们可以看到fputc函数的功能是将一个字符写入流中,我们来举个实例:
这里我们将26个英文字母放入文件中。
int main()
{
FILE* pf = fopen("text.txt","w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
char a = 'a';
for (int i = 0; i < 26; i++)
{
fputc(a+i, pf);
}
fclose(pf);
pf = NULL;
return 0;
}
需要注意的是:当文件以"w"的形式打开,文件原先的内容会被清空。
写入26个英文字母后,我们打开文件查看一下:
(4)fgetc
我们来看看这个函数的定义
可以看出这个函数的功能是从流中拿一个字符。
我们基于fputc函数的实例,再从文件从拿出26个字符。
int main()
{
FILE* pf = fopen("text.txt","r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
char a ;
for (int i = 0; i < 26; i++)
{
printf("%c", fgetc(pf));
}
fclose(pf);
pf = NULL;
return 0;
}
注意此时是以"r"模式即读的方式拿出文件中的字符。
(5)fputs
我们来看这个函数的定义
可以看到这个函数的功能是向流中写入一个字符串。如果写入成功,返回一个非负值。如果写入失败,返回EOF。
实例如下:我们向文件中写入“hello world”
int main()
{
FILE* pf = fopen("text.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
char a[100]="hello world";
fputs(a, pf);
fclose(pf);
pf = NULL;
return 0;
}
(6)fgets
我们来看这个函数的定义
我们可以看到这个函数有3个参数,功能是从流中拿取字符串,第二个参数num是从流中拿取字符的个数。如果读取成功函数返回值是返回拿取的字符串的首地址,若读取错误或者在读取到任意一个字符前遇到了文件末尾,则返回一个空指针。我们照样举一个实例。
注意:fgets这个函数实际上只会读取num-1个字符,因为最后一个字符的位置编译器会用来放\0
int main()
{
FILE* pf = fopen("text.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
char a[100];
printf("%s", fgets(a,26,pf));
fclose(pf);
pf = NULL;
return 0;
}
(7)sscanf
我们来看看这个函数的定义:
这个函数功能是在字符串中读取格式化的数据,见实例:
int main()
{
char arr[30] = "this is 2024!";
char str[20];
char strr[20];
int i;
sscanf(arr, "%s %s %d", str,strr, &i);
printf("%s\n",str);
printf("%s\n", strr);
printf("%d\n", i);
return 0;
}
结果如下:
(8)sprintf
我们来看看sprintf函数的定义:
我们可以看到这个函数的作用是将格式化的数据写入字符串,举个实例看看:
int main()
{
char arr[30];
char str[20]="say";
char strr[20] = "so";
int i = 25;
sprintf(arr, "%s %s %d", str, strr, i);
printf("%s", arr);
return 0;
}
scanf、fscanf、sscanf和printf、fprintf、sprintf的区别
你可能一眼就能看出来,这些函数长得非常相似,那它们的区别在哪里呢?见下表:
函数 | 功能 |
scanf | 从标准输入流上读取格式化的数据 |
fscanf | 从指定的输入流上读取格式化的数据 |
sscanf | 在字符串中读取格式化的数据 |
printf | 把数据以格式化的形式打印在标准输出流上 |
fprintf | 把数据以格式化的形式打印在标准输出流上 |
sprintf | sprintf把格式化的数据转化成字符串 |
五、文件位置相关函数
(1)fseek函数
我们来看看fseek函数的定义:
我们可以看到,这个函数的功能是重新定位流位置指示器(即光标)
第一个参数是指向待修改的文件的文件指针
第二个参数是偏移量,向左偏移则为负数,向右偏移则为正数(以字节为单位)
第三个参数是开始偏移的起始位置,<stdio.h>对从文件末尾、光标当前位置还是文件起始位置开始偏移定义了3个宏,如下:
SEEK_SET | 文件的起始处 |
SEEK_CUR | 文件的当前位置 |
SEEK_END | 文件的末尾处 |
我们依旧举一个实例看看,此时待读取的文件里面放的是myworld,初始的时候光标在内容的最前面:
此时,我们让光标向后移动两个位置,对world进行输出:
代码如下:
int main()
{
FILE* pf = fopen("text.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fseek(pf,2, SEEK_SET);
char a[100];
printf("%s", fgets(a, 6, pf));
fclose(pf);
pf = NULL;
return 0;
}
结果:
(2)ftell
此时我们再来看看ftell函数,定义如下:
可以看到,这个函数的功能是获取当前光标在流中的位置,我们基于上面fseek函数向右偏移两个位置的情况来举例,实例如下:
int main()
{
FILE* pf = fopen("text.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fseek(pf,2, SEEK_SET);
/*char a[100];
printf("%s", fgets(a, 6, pf));*/
printf("%d", ftell(pf));
fclose(pf);
pf = NULL;
return 0;
}
此时是否会输出2呢?
如我们所想,输出的是2。
(3)rewind
这个函数的功能是将文件位置(光标)设置在起始处
注:调用 rewind(fp)几乎等价于 fseek(fp, 0L, SEEK_SET),两者的差异是 rewind 函数不返回值,但会为 fp 清除错误指示器。
我们也为这个函数举一个实例:
int main()
{
FILE* pf = fopen("text.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fseek(pf, 2, SEEK_SET);
printf("fseek偏移2个后,位置在:%d处\n", ftell(pf));
rewind(pf);
printf("rewind函数后,位置在:%d处", ftell(pf));
fclose(pf);
pf = NULL;
return 0;
}
(4)feof
我们可以看到feof函数是用来检查文件末尾的函数,当文件是遇到末尾时,它会返回一个非0值,其它情况则返回一个0。
(5)ferror
这个函数用于检测读取是否发生错误,当读取发生错误时,返回一个非0值,其它情况返回一个0。
六、文件缓冲
这里有两个函数可以对缓冲区进行 清洗/刷新:fflush、fclose。
是的,fclose在关闭文件时,也会刷新缓冲区。
练习:复制文件
使用上面讲到的内容,将其中一个文件中的内容,复制到另外一个文件中去。
int main()
{
FILE* pf1 = fopen("practice.txt", "r");
FILE* pf2 = fopen("practice_copy.txt", "w");
if (pf1 == NULL)
{
perror("fopen1");
return 1;
}
if (pf2 == NULL)
{
perror("fopen2");
return 1;
}
int c=0;
while ((c=fgetc(pf1) )!= EOF)
{
fputc(c, pf2);
}
fclose(pf1);
pf1 = NULL;
fclose(pf2);
pf2 = NULL;
return 0;
}