C fgets 函数
最后修改日期:2025 年 4 月 6 日
fgets
函数是 C 语言编程中用于安全地从文件或标准输入读取行的基本工具。与 gets
不同,它通过限制输入大小来防止缓冲区溢出。本教程将深入探讨 fgets
,涵盖其参数、返回值和实际应用。掌握 fgets
可以确保您的 C 程序具有健壮的输入处理能力。
什么是 fgets?
fgets
函数从指定流中读取一行并将其存储在缓冲区中。它需要三个参数:用于存储输入的缓冲区、要读取的最大字符数以及输入流。与 gets
不同,它会将换行符包含在缓冲区中,并始终以 null 终止字符串。fgets
在成功时返回缓冲区指针,在出错或到达文件末尾时返回 NULL
。
基本的 fgets 语法
fgets
的函数原型是
char *fgets(char *str, int n, FILE *stream);
str
是目标缓冲区,n
是要读取的最大字符数(包括 null 终止符),stream
是输入源。该函数一直读取,直到遇到换行符、EOF 或已读取 n-1 个字符。生成的字符串始终以 null 终止。
从标准输入读取
此示例演示了如何使用 fgets
从键盘(stdin)读取用户输入。
#include <stdio.h> int main() { char name[50]; printf("Enter your name: "); fgets(name, sizeof(name), stdin); // Safe input with size limit printf("Hello, %s", name); return 0; }
在这里,fgets
从 stdin
读取到 name
缓冲区,最大为 49 个字符(加上 null 终止符)。与 scanf
不同,它可以安全地处理输入中的空格。如果输入中存在换行符,它会被包含在缓冲区中。
从文件读取
此示例展示了如何使用 fgets
逐行读取文件。
#include <stdio.h> int main() { FILE *fp; char line[100]; fp = fopen("data.txt", "r"); if (fp == NULL) { perror("Error opening file"); return 1; } while (fgets(line, sizeof(line), fp) != NULL) { printf("%s", line); // Print each line } fclose(fp); return 0; }
该程序打开 "data.txt" 并逐行读取。当到达文件末尾或遇到错误时,fgets
返回 NULL
。每行在读取时都会被打印出来,保留原始格式,包括换行符。缓冲区大小(100)决定了可以安全读取的最大行长度。
处理长行
此示例演示了如何处理大于缓冲区大小的行。
#include <stdio.h> #include <string.h> int main() { char buffer[10]; int complete = 0; while (!complete) { fgets(buffer, sizeof(buffer), stdin); // Check if line was fully read if (strchr(buffer, '\n') != NULL) { complete = 1; } printf("Partial: %s", buffer); } return 0; }
当行超出缓冲区大小时,fgets
只会读取其中的一部分。此代码会检查换行符以检测完整的行。循环一直进行,直到找到换行符,从而分块处理长输入。当内存有限或处理非常长的行时,此技术非常有用。
移除换行符
此示例展示了如何移除 fgets
在输出中包含的尾随换行符。
#include <stdio.h> #include <string.h> int main() { char input[50]; printf("Enter text: "); fgets(input, sizeof(input), stdin); // Remove trailing newline if present input[strcspn(input, "\n")] = '\0'; printf("You entered: '%s'\n", input); return 0; }
strcspn
函数找到第一个换行符并将其替换为 null 终止符。这会创建一个不带换行符的更干净的字符串。此技术在比较字符串或存储用户输入时特别有用。请注意,如果输入被截断,可能没有换行符可供移除。
将 fgets 与其他输入函数进行比较
此示例将 fgets
与 scanf
和 gets
进行对比。
#include <stdio.h> int main() { char buffer1[20]; char buffer2[20]; char buffer3[20]; // Unsafe gets (deprecated) printf("Enter text (gets): "); gets(buffer1); // Dangerous - no bounds checking // scanf with %s (stops at whitespace) printf("Enter text (scanf): "); scanf("%19s", buffer2); // Limited protection // Safe fgets printf("Enter text (fgets): "); fgets(buffer3, sizeof(buffer3), stdin); printf("\ngets: %s\n", buffer1); printf("scanf: %s\n", buffer2); printf("fgets: %s\n", buffer3); return 0; }
gets
是危险的,因为它不限制输入大小。带有 %s
的 scanf
更安全,但会在遇到空格时停止。fgets
是最安全的选择,它可以在限制大小的情况下读取整行。这次比较突显了为什么在现代 C 代码中,fgets
是实现健壮输入处理的首选。
读取多行
此示例演示了如何读取多行,直到输入空行。
#include <stdio.h> #include <string.h> int main() { char line[100]; printf("Enter lines (blank to quit):\n"); while (1) { fgets(line, sizeof(line), stdin); // Check for blank line (just newline) if (strcmp(line, "\n") == 0) { break; } printf("You entered: %s", line); } printf("Goodbye!\n"); return 0; }
程序会继续读取行,直到遇到空行(仅换行符)。每输入一行都会被处理。这种模式在需要接受多行输入的交互式程序中很常见。空行作为一种简单但有效的终止条件。
fgets 的错误处理
此示例展示了使用 fgets
时的正确错误处理。
#include <stdio.h> #include <errno.h> #include <string.h> int main() { FILE *fp; char line[100]; fp = fopen("nonexistent.txt", "r"); if (fp == NULL) { fprintf(stderr, "Error %d: %s\n", errno, strerror(errno)); return 1; } if (fgets(line, sizeof(line), fp) == NULL) { if (feof(fp)) { printf("Reached end of file\n"); } else { perror("Error reading file"); } } else { printf("First line: %s", line); } fclose(fp); return 0; }
此代码展示了全面的错误处理。它会检查文件打开错误,并区分文件结束和其他读取错误。feof
函数专门用于测试文件结束条件。正确的错误处理可以使程序更加健壮,并在出现问题时更容易调试。
使用 fgets 的最佳实践
- 始终指定缓冲区大小:使用 sizeof(buffer) 或常量来防止缓冲区溢出。
- 检查返回值:在使用缓冲区之前,请验证 fgets 是否返回了非 NULL 值。
- 处理换行符:如果需要,使用 strcspn 或类似方法移除尾随换行符。
- 在需要时清除 stdin:在 fgets 之后,使用 while(getchar()!='\n'); 来清除多余的输入。
- 与 sscanf 结合使用:对于解析,请先使用 fgets,然后使用 sscanf 进行更安全的输入处理。
来源
本教程深入探讨了 fgets
函数,从基本用法到高级技术。通过遵循这些示例和最佳实践,您可以在 C 程序中实现安全可靠的输入处理。
作者
列表 C 标准库。