ZetCode

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)读取用户输入。

stdin_read.c
#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;
}

在这里,fgetsstdin 读取到 name 缓冲区,最大为 49 个字符(加上 null 终止符)。与 scanf 不同,它可以安全地处理输入中的空格。如果输入中存在换行符,它会被包含在缓冲区中。

从文件读取

此示例展示了如何使用 fgets 逐行读取文件。

file_read.c
#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)决定了可以安全读取的最大行长度。

处理长行

此示例演示了如何处理大于缓冲区大小的行。

long_lines.c
#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 在输出中包含的尾随换行符。

strip_newline.c
#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 与其他输入函数进行比较

此示例将 fgetsscanfgets 进行对比。

input_comparison.c
#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 是危险的,因为它不限制输入大小。带有 %sscanf 更安全,但会在遇到空格时停止。fgets 是最安全的选择,它可以在限制大小的情况下读取整行。这次比较突显了为什么在现代 C 代码中,fgets 是实现健壮输入处理的首选。

读取多行

此示例演示了如何读取多行,直到输入空行。

multi_line.c
#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 时的正确错误处理。

error_handling.c
#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 的最佳实践

来源

C fgets 文档

本教程深入探讨了 fgets 函数,从基本用法到高级技术。通过遵循这些示例和最佳实践,您可以在 C 程序中实现安全可靠的输入处理。

作者

我的名字是 Jan Bodnar,我是一名充满热情的程序员,对编码有着浓厚的兴趣。自 2007 年以来,我通过 1,400 多篇文章和 8 本电子书分享我的专业知识。凭借十多年的教学经验,我致力于让编程变得易于理解且引人入胜。

列表 C 标准库