c语言 fgets stdin

99ANYc3cd6
预计阅读时长 19 分钟
位置: 首页 C语言 正文

fgets 是什么?

fgets 是 "file string get" 的缩写,它是一个 C 标准库函数,用于从指定的流(stream)中读取一行字符串。

scanfgets 不同,fgets 的一个关键优点是可以防止缓冲区溢出,因为它允许你指定读取的最大字符数。

函数原型

char *fgets(char *str, int n, FILE *stream);

参数详解:

  1. char *str:

    • 这是一个字符指针,指向一个字符数组(也就是缓冲区)。
    • fgets 会将从流中读取的字符存入这个缓冲区。
    • 调用者必须负责提供一个足够大的内存空间。
  2. int n:

    • 这是一个整数,表示最多要读取的字符数(包括结尾的换行符 \n 和空字符 \0
    • 这是 fgets 安全性的关键所在,它最多会读取 n-1 个字符,然后自动在第 n 个位置添加一个空字符 \0 来结束字符串。
    • 如果一行中的字符数(包括 \n)超过了 n-1,那么多余的字符会留在输入流中,等待下一次读取。
  3. FILE *stream:

    • 这是一个指向 FILE 对象的指针,代表了你要读取的输入源。
    • 当你想从键盘读取输入时,这个参数就是 stdin,它是在 stdio.h 中定义的标准输入流。

返回值:

  • 成功: 返回指向 str 的指针(也就是你传入的第一个参数)。
  • 失败或到达文件末尾: 返回 NULL 指针,当发生错误(比如流发生错误)或遇到文件结束符(EOF, End-Of-File)时,fgets 会返回 NULL,在 Windows 上,你可以通过组合键 Ctrl+Z 然后按 Enter 来模拟输入 EOF;在 Linux/macOS 上,是 Ctrl+D

stdin 读取输入的基本用法

这是一个最简单的例子,从键盘读取一行输入并打印出来。

#include <stdio.h>
int main() {
    char buffer[100]; // 定义一个足够大的缓冲区
    printf("请输入一行文字: ");
    // 从 stdin 读取最多 sizeof(buffer) - 1 个字符
    // sizeof(buffer) 是 100,所以最多读取 99 个字符
    // 第 100 个位置留给 '\0'
    if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
        // 成功读取
        printf("你输入的内容是: %s", buffer);
    } else {
        // 读取失败或遇到 EOF
        printf("读取输入失败或遇到文件结束符,\n");
    }
    return 0;
}

代码解释:

  1. char buffer[100];:我们创建了一个可以容纳 100 个字符的数组。
  2. fgets(buffer, sizeof(buffer), stdin);
    • buffer:数据将存入这个数组。
    • sizeof(buffer):计算出数组的大小是 100。fgets 最多会读取 99 个字符。
    • stdin:表示从键盘读取。
  3. if (fgets(...) != NULL):这是一个良好的编程习惯,我们检查 fgets 是否成功执行,如果用户直接按 Ctrl+Z (Windows) 或 Ctrl+D (Linux/macOS),fgets 会返回 NULL,程序会进入 else 分支。
  4. printf("你输入的内容是: %s", buffer);:打印出读取到的内容。

一个非常重要的细节:换行符 \n 的处理

fgets 的一个行为与很多人直觉不同:它会保留输入行末尾的换行符 \n

让我们看一个例子:

#include <stdio.h>
#include <string.h> // 用于 strlen
int main() {
    char buffer[50];
    printf("请输入你的名字: ");
    fgets(buffer, sizeof(buffer), stdin);
    // 使用 strlen 打印字符串的实际长度
    printf("buffer 的内容: \"%s\"\n", buffer);
    printf("buffer 的长度: %zu\n", strlen(buffer)); // %zu 用于打印 size_t 类型
    return 0;
}

可能的输入和输出:

请输入你的名字: Alice
buffer 的内容: "Alice\n"
buffer 的长度: 6  // 'A','l','i','c','e','\n'

你会发现,buffer 的内容里包含了换行符 \n,这在大多数情况下都不是我们想要的,因为我们通常希望得到一个纯粹的字符串("Alice"),而不是 "Alice\n"。

如何去除换行符?

你需要手动检查并去除它,一个通用的方法是:

#include <stdio.h>
#include <string.h>
void remove_newline(char *str) {
    // 查找换行符的位置
    size_t len = strlen(str);
    if (len > 0 && str[len - 1] == '\n') {
        // 如果找到,就将它替换为字符串结束符 '\0'
        str[len - 1] = '\0';
    }
}
int main() {
    char buffer[50];
    printf("请输入你的名字: ");
    fgets(buffer, sizeof(buffer), stdin);
    remove_newline(buffer); // 调用函数去除换行符
    printf("处理后的 buffer: \"%s\"\n", buffer);
    printf("处理后的长度: %zu\n", strlen(buffer));
    return 0;
}

现在运行结果:

请输入你的名字: Alice
处理后的 buffer: "Alice"
处理后的长度: 5

这个 remove_newline 函数非常实用,建议你将其加入自己的工具函数库中。


fgetsscanf 的对比

特性 fgets scanf
安全性 ,可以指定最大读取长度,防止溢出。 ,容易导致缓冲区溢出,且难以控制。
读取整行,包括空格,直到遇到换行符。 默认以空白字符(空格、Tab、换行)作为分隔符,无法直接读取带空格的字符串。
换行符处理 会保留换行符 \n 在字符串中,需要手动去除。 不会保留换行符,换行符会留在输入流中,可能影响后续的输入。
主要用途 读取一行文本、命令行参数、配置文件等。 格式化输入,如读取整数、浮点数等。

为什么推荐使用 fgets

在现代 C 语言编程中,当你需要从用户那里读取字符串时,强烈推荐使用 fgetsscanf 虽然灵活,但在处理字符串输入时非常脆弱,容易出错。fgets 提供了更可控、更安全的方式来处理输入。


完整示例:一个简单的循环读取器

这个例子展示了如何使用 fgets 创建一个循环,持续读取用户输入,直到用户输入 "exit" 或遇到文件结束符。

#include <stdio.h>
#include <string.h>
#include <ctype.h> // 用于 strcasecmp (非标准,但常用) 或自己实现不区分大小写的比较
#define BUFFER_SIZE 256
// 一个简单的去除换行符的函数
void remove_newline(char *str) {
    size_t len = strlen(str);
    if (len > 0 && str[len - 1] == '\n') {
        str[len - 1] = '\0';
    }
}
int main() {
    char input[BUFFER_SIZE];
    printf("--- 简单的回声程序 (输入 'exit' 退出) ---\n");
    while (1) {
        printf("> ");
        // 读取输入
        if (fgets(input, BUFFER_SIZE, stdin) == NULL) {
            // 用户输入了 EOF (Ctrl+Z / Ctrl+D)
            printf("\n检测到文件结束符,程序退出,\n");
            break;
        }
        // 去除换行符
        remove_newline(input);
        // 检查用户是否想退出
        // 注意: strcasecmp 是一个非标准函数,但很多编译器都支持。
        // 如果要严格遵循标准,可以自己实现一个不区分大小写的比较函数。
        // 或者使用 strcmp(input, "exit") 进行区分大小写的比较。
        #ifdef __STDC_LIB_EXT1__ // 或者直接使用,很多环境都支持
            if (strcasecmp(input, "exit") == 0) {
        #else
            if (strcmp(input, "exit") == 0) { // 使用标准库的 strcmp
        #endif
            printf("再见!\n");
            break;
        }
        // 回显用户输入
        printf("你输入了: %s\n", input);
    }
    return 0;
}
  • fgets(str, n, stdin) 是从标准输入安全读取一行字符串的首选方法。
  • 核心参数 n 控制了读取的最大长度,有效防止了缓冲区溢出。
  • 必须处理换行符 \nfgets 会保留它,通常需要手动去除。
  • 始终检查返回值,判断是成功读取还是遇到了文件结束符或错误。
  • 相比 scanffgets 在处理字符串输入时更安全、更可靠。
-- 展开阅读全文 --
头像
C语言如何调用Windows API?
« 上一篇 2025-12-31
织梦 banner手机浏览
下一篇 » 01-01

相关文章

取消
微信二维码
支付宝二维码

目录[+]