函数对比
scanf,fscanf,sscanf
scanf、fscanf 和 sscanf 是 C 语言中用于输入操作的函数,特别是用于格式化输入。它们属于标准输入/输出库,用于按照指定格式从不同来源读取数据。
以下是它们的基本详情和区别:
scanf ( ):
用途:它从标准输入流(stdin)读取输入,通常是键盘。
格式:int scanf(const char *format, …);
目的:用于根据提供的格式说明符从标准输入读取各种数据类型。
示例:读取一个整数和一个字符。
int i; char c; scanf("%d %c", &i, &c); 1 2 3 fscanf ( ):
用途:它从文件流读取输入,不仅限于 stdin。
格式:int fscanf(FILE *stream, const char *format, …);
目的:它类似于 scanf,但可用于任何使用 fopen 函数打开的文件或任何预定义的文件流。这允许从文件或其他输入流读取格式化输入。
示例:从文件中读取一个整数。
FILE *fp; int n; fp = fopen("file.txt", "r"); if(fp != NULL) { fscanf(fp, "%d", &n); fclose(fp); }
sscanf 函数
sscanf 函数用于从字符串中按指定格式读取数据,这对于解析字符串中的特定数据非常有用
int sscanf(const char *str, const char *format, ...);
1
str:要读取数据的源字符串。
format:格式字符串,指定了希望从源字符串中读取数据的类型和格式。
‘…’:额外的参数,用于存储从源字符串中按照格式字符串读取的数据。
返回值:返回成功读取的数据项的数量。如果在读取任何数据之前遇到错误或到达字符串的结尾,则返回EOF
假设你有一个包含整数和浮点数的字符串,你想从中提取这些数值:
1. #include 2. 3. int main() { 4. char *str = "100 3.14"; 5. int i; 6. float f; 7. 8. int result = sscanf(str, "%d %f", &i, &f); 9. 10. if (result == 2) { 11. printf("整数:%d\n", i); 12. printf("浮点数:%f\n", f); 13. } else { 14. printf("格式化读取失败\n"); 15. } 16. 17. return 0; 18. }
在这个例子中,sscanf 会尝试从字符串 “100 3.14” 中读取一个整数和一个浮点数。如果成功,它会返回读取的项数(在这个例子中是2),并且变量 i 和 f 将分别被赋值为100和3.14。
注意事项
安全性:与其他格式化输入函数一样,使用 sscanf 时需注意安全性,特别是对字符串的长度和格式的处理,以避免溢出等问题。
错误处理:检查 sscanf 的返回值来确认成功读取的数据项数量,这对于验证和错误处理很重要。
使用场景:sscanf 特别适用于从已经存在的字符串中提取数据,例如解析来自文件、网络或用户输入的数据。
printf , fprintf , sprintf
printf 函数
int printf(const char *format, ...);
用途:将格式化的输出发送到标准输出,通常是屏幕(控制台)。
format:格式字符串,指定了输出的格式。
‘…’:可变参数列表,包含要输出的数据。
示例:向控制台打印整数和字符串。
int num = 10; char *arr = "Hello, world!"; printf("Number: %d, arr: %s\n", num, arr);
fprintf 函数
int fprintf(FILE *stream, const char *format, ...);
1
用途:将格式化的输出发送到指定的文件流中,可以是任何 FILE 类型的流,包括标准输出(stdout)和标准错误(stderr)。
示例:向文件写入格式化文本。
1. FILE *fp = fopen("output.txt", "w"); 2. if (fp != NULL) { 3. fprintf(fp, "Number: %d\n", num); 4. fclose(fp); 5. }
sprintf函数
sprintf 函数用于将格式化的数据写入字符串。它是标准输入输出库中的一个重要函数,特别适用于创建格式化字符串
int sprintf(char *str, const char *format, ...);
1
返回值:返回写入到目标字符串的字符数,不包括终结的空字符(‘\0’)。如果发生错误,则可能返回负值。
假设您想将一个整数和一个浮点数格式化为一个字符串:
1. #include 2. 3. int main() { 4. int num = 25; 5. float pi = 3.14159; 6. char buffer[50]; 7. 8. sprintf(buffer, "%d, %f", num, pi); 9. 10. printf("格式化后的字符串:%s\n", buffer); 11. 12. return 0; 13. }
在这个例子中,sprintf 将整数 num 和浮点数 pi 按指定的格式写入字符串 buffer。之后,可以使用 printf 打印这个字符串,或者以其他方式使用它。
文件的随机读写
顺序读写数据是按照顺序一个接一个地读取或写入的,通常从文件的开始位置开始,然后逐步向后移动,直到文件结束。
而随机读写允许直接跳转到文件中的任何位置进行读取或写入。不必遵循特定的顺序,可以访问文件的任何部分
fseek函数
fseek 函数用于在文件中移动文件指针到指定位置,从而实现文件的随机访问
int fseek(FILE *stream, long offset, int origin);
offset:相对于 origin 参数所指定位置的偏移量,以字节为单位。
origin:起始位置,它可以是 SEEK_SET(文件开头)、==SEEK_CUR(当前位置)==或 SEEK_END(文件末尾)
先举一个例子:
int main() { FILE* pf = fopen("test2.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } int ch = fgetc(pf); printf("%c\n", ch); ch = fgetc(pf); printf("%c\n", ch); ch = fgetc(pf); printf("%c\n", ch); fclose(pf); pf = NULL; return 0; }
在test2.txt中我们放入abcdefgh,打印结果
这里,移动文件指针按照顺序移动,那么如果我想让指针重新指向a呢?这里就得使用fseek函数:
fseek(pf,-3, SEEK_CUR);
这里从当前位置移动,-3即为向文件开头方向移动.
打印结果:
fseek(pf,0, SEEK_SET);
这种写法是从起始位置偏移0个字符,所以还是起始位置
ftell函数
若现在不知道偏移量是多少,就可以使用ftell函数;
long ftell(FILE *stream);
比如上面的例子:
int main() { FILE* pf = fopen("test2.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } int ch = fgetc(pf); printf("%c\n", ch); ch = fgetc(pf); printf("%c\n", ch); ch = fgetc(pf); printf("%c\n", ch); int n = ftell(pf); printf("%d\n", n); fseek(pf,0, SEEK_SET); ch = fgetc(pf); printf("%c\n", ch); fclose(pf); pf = NULL; return 0; }
这里用n来接收偏移量,打印结果:
我们也可以用这个函数来判断文件有多少个字节:
先用fseek将指针移动到末尾
再用ftell函数;
rewind函数
rewind用于将文件的位置指针重置到文件的开始位置。它的功能类似于使用 fseek 函数来将文件指针移动到文件开头,但 rewind 不返回值,因此不能用来检测错误。
1. void rewind(FILE *stream); 2. 1 3. int main() 4. { 5. FILE* pf = fopen("test2.txt", "r"); 6. if (pf == NULL) 7. { 8. perror("fopen"); 9. return 1; 10. } 11. int ch = fgetc(pf); 12. printf("%c\n", ch); 13. 14. ch = fgetc(pf); 15. printf("%c\n", ch); 16. 17. ch = fgetc(pf); 18. printf("%c\n", ch); 19. 20. ch = fgetc(pf); 21. printf("%c\n", ch); 22. 23. rewind(pf); 24. 25. ch = fgetc(pf); 26. printf("%c\n", ch); 27. 28. fclose(pf); 29. pf = NULL; 30. return 0; 31. }
还以这串代码为例,rewind函数调用后,移动指针指向起始位置,打印结果为a
文件读取结束的判定
feof和ferror函数
feof 和 ferror 是用于检查文件状态的两个不同函数,它们分别用于检测文件流的结束-of-file (EOF) 状态和读写错误。
feof
int feof(FILE *stream);
feof 用于检查是否已经读取到文件的末尾。它检查与文件流关联的 EOF 标志位。
如果已经达到文件末尾,返回非零值;否则,返回 0
1. FILE *filePointer = fopen("file.txt", "r"); 2. // ... 文件读取操作 ... 3. 4. if (feof(filePointer)) { 5. // 已到达文件末尾 6. } 7. 1 8. 2 9. 3 10. 4 11. 5 12. 6 13. ferror 14. 15. int ferror(FILE *stream)
ferror 用于检查文件流是否因为错误而无法继续读取或写入
如果文件流有错误,返回非零值;否则,返回 0
注意点
EOF and 错误:feof 和 ferror 检查的是不同的情况:feof 是检查是否到达文件末尾,而 ferror 是检查文件操作是否发生错误。
循环中使用:在循环中读取文件时,应当检查这两个函数来确保正确处理文件末尾和可能发生的错误。
feof 的误用:经常有误用 feof 的情况,即在循环条件中直接使用 feof。正确的方法是在读取操作后检查 feof。因为只有在尝试读取超过文件末尾之后,EOF 标志才会被设置。
判断方式
文本文件读取是否结束,判断返回值是否为EOF( fgetc),或者NULL(fgets)
二进制文本的读取结束判断,判断返回值是否小于实际要读的个数,例如
fread判断返回值是否小于实际要求的个数
使用 fgetc 读取文件的示例:
#include int main() { FILE *file = fopen("example.txt", "r"); if (file == NULL) { perror("fopen"); return 1; } int c; // 注意:int 类型用于存储 EOF // 使用 fgetc 逐字符读取文件,直到文件结束 while ((c = fgetc(file)) != EOF) { putchar(c); // 输出字符 } // 检查是否因为文件末尾才停止读取 if (feof(file)) { puts("\n文件已读取完毕"); } else if (ferror(file)) { perror("读取文件时发生错误"); } fclose(file); return 0; }
使用 fread 读取文件的示例:
1. #include 2. 3. int main() { 4. FILE *file; 5. int number; 6. 7. // 打开文件用于二进制读取 8. file = fopen("output.txt", "rb"); 9. if (file == NULL) { 10. perror("Error opening file"); 11. return 1; 12. } 13. 14. // 使用fread读取二进制数 15. size_t itemsRead = fread(&number, sizeof(int), 1, file); 16. if (itemsRead == 1) { 17. printf("读取的整数是:%d\n", number); 18. } else { 19. // 如果没有读取到一个整数,打印错误信息 20. if (feof(file)) { 21. printf("文件结束,未读取到数据。\n"); 22. } 23. if (ferror(file)) { 24. printf("读取文件时出错。\n"); 25. } 26. } 27. 28. // 关闭文件 29. fclose(file); 30. 31. return 0; 32. }
文件缓冲区
缓冲区在计算机科学中是一块内存区域,用于临时存放数据,目的是在数据在发送者和接收者之间传输时调节和平衡数据流。在 I/O 操作的上下文中,缓冲区的主要作用是减少对硬件设备(如硬盘、网络设备等)的直接访问次数,提高数据处理的效率和吞吐量。
标准库提供的文件操作函数(如 fread、fwrite、printf、scanf 等)通常都会使用这些缓冲区
功能和使用
提高性能:缓冲区可以减少对底层 I/O(输入/输出) 系统的调用次数,因为数据是在缓冲区中累积起来,然后一次性进行读写,这通常可以提高性能。
缓冲区管理:C 标准库提供了一系列函数来管理和控制缓冲区,如 setbuf、setvbuf 等。
刷新缓冲区:在需要时,可以使用 fflush 函数手动刷新输出缓冲区,将缓冲区内的数据写入实际的 I/O 设备中。例如,可能需要在写入文件后立即刷新缓冲区,以确保数据被物理写入磁盘。
关闭文件:在关闭文件时(使用 fclose),缓冲区会自动被刷新。
例如,在 C 中,FILE 结构就关联了一个缓冲区。当你使用 fopen 打开一个文件时,系统会自动分配一个缓冲区,你可以使用 setvbuf 来更改其缓冲行为。当你读写数据时,例如使用 fread 或 fwrite 函数,这些数据会传递通过这个缓冲区,从而提高读写操作的效率。
在文本编辑器中,用户的输入通常存储在缓冲区内直到按下 “保存” 按钮时才写入硬盘。在网络通信中,数据包可能会首先存储在缓冲区内,然后一起发送以减少网络传输开销。在视频流媒体播放中,视频数据可以预先存储在缓冲区内,以避免播放时由于网络延迟导致的卡顿。
本章内容到此结束!感谢大家的观看!!
————————————————