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 标准库。