C语言fgets函数有何用法与注意事项?

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

C语言 fgets 函数详解

fgets 是 C 标准库 <stdio.h> 中一个非常重要且常用的函数,用于从指定的流(如标准输入 stdin、文件等)中读取一行字符串。

C语言fgets函数 C语言中文网
(图片来源网络,侵删)

函数原型

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

参数详解

fgets 函数接受三个参数:

  1. *`char str`**:

    • 这是一个字符指针(或字符数组的首地址)。
    • 它的作用是存储从流中读取到的内容。
    • 你需要预先分配足够的内存空间来存放读取到的字符串,如果使用数组,数组的大小必须足够大。
  2. int n:

    • 这是一个整数,表示最多要读取的字符数(包括结尾的空字符 \0
    • 这是 fgets 一个非常关键的安全特性,可以有效防止缓冲区溢出
    • fgets 最多会读取 n-1 个字符,然后在末尾自动添加一个空字符 \0 来构成一个合法的 C 字符串。
  3. *`FILE stream`**:

    C语言fgets函数 C语言中文网
    (图片来源网络,侵删)
    • 这是一个指向 FILE 对象的指针,代表了要读取的输入流。
    • 可以是标准输入流 stdin(代表键盘输入),也可以是通过 fopen 函数打开的文件指针。
    • stdinfpFILE *fp = fopen("test.txt", "r");)。

返回值

fgets 函数的返回值是一个指针,有三种情况:

  • 成功: 返回 str,即指向存储读取内容的缓冲区的首地址。
  • 遇到文件结束符: 如果在读取任何字符之前就到达了流的末尾(从文件末尾读取或用户按下了 Ctrl+D / Ctrl+Z),则返回 NULL 指针。
  • 读取出错: 如果在读取过程中发生错误(读取文件时发生 I/O 错误),也会返回 NULL 指针。

重要提示: 当 fgets 返回 NULL 时,你需要通过检查 feof(stream)ferror(stream) 来区分是“到达文件末尾”还是“发生错误”。

工作原理

fgets 的工作流程如下:

  1. stream 指定的流中读取字符。
  2. 读取过程在以下三种情况下会停止:
    • 已经读取了 n-1 个字符。
    • 读取到了换行符 \n,换行符 \n 会被包含在读取到的字符串中。
    • 到达了流的末尾(EOF)。
  3. 无论在哪种情况下停止,fgets 都会在读取到的所有字符的末尾自动添加一个空字符 \0,使其成为一个标准的 C 语言字符串。

从标准输入 stdin 读取(键盘输入)

这是 fgets 最常见的用途之一,用于安全地获取用户输入的一行字符串。

C语言fgets函数 C语言中文网
(图片来源网络,侵删)

示例1:基本用法

#include <stdio.h>
#define BUFFER_SIZE 100
int main() {
    char name[BUFFER_SIZE];
    printf("请输入您的名字: ");
    // 从标准输入读取最多 BUFFER_SIZE-1 个字符,存入 name 数组
    if (fgets(name, BUFFER_SIZE, stdin) != NULL) {
        // 成功读取
        printf("您好, %s", name); // 注意:name 中包含了换行符 \n
    } else {
        // 读取失败或遇到 EOF
        printf("输入发生错误或已结束,\n");
    }
    return 0;
}

运行示例:

请输入您的名字: 张三
您好, 张三

分析: 用户输入 "张三" 并按下回车。fgets 读取了 "张三" 和回车符 \n,总共 4 个字符(在中文环境下,"张三"算两个字符,加上 \n 共3个),然后在末尾加上 \0name 数组的内容是 {'张', '三', '\n', '\0'}printf 输出时,%s 会一直打印到 \0\n 也会被输出,导致光标换到了下一行。

示例2:处理换行符

在很多情况下,我们不希望字符串末尾包含换行符,我们可以手动将它去掉。

#include <stdio.h>
#include <string.h> // 用于 strlen 函数
#define BUFFER_SIZE 100
int main() {
    char city[BUFFER_SIZE];
    printf("请输入您所在的城市: ");
    if (fgets(city, BUFFER_SIZE, stdin) != NULL) {
        // 检查最后一个字符是否是换行符
        size_t len = strlen(city);
        if (len > 0 && city[len - 1] == '\n') {
            // 如果是,则将其替换为字符串结束符 \0
            city[len - 1] = '\0';
        }
        printf("您来自: %s\n", city); // 现在输出不会多一个空行了
    }
    return 0;
}

运行示例:

请输入您所在的城市: 北京
您来自: 北京

分析: strlen(city) 返回字符串长度(不包括 \0),如果最后一个字符是 \n,我们就用 city[len - 1] = '\0'; 将它覆盖掉,字符串就在 \n 的位置提前结束了。

从文件中读取

fgets 同样非常适合逐行读取文本文件。

示例3:逐行读取文件

假设我们有一个名为 poem.txt 的文件,内容如下:

床前明月光,
疑是地上霜。
举头望明月,
低头思故乡。

读取该文件的代码:

#include <stdio.h>
#define LINE_LENGTH 256
int main() {
    FILE *fp;
    char line[LINE_LENGTH];
    // 以只读方式打开文件
    fp = fopen("poem.txt", "r");
    if (fp == NULL) {
        perror("无法打开文件 poem.txt");
        return 1;
    }
    printf("文件内容如下:\n");
    printf("--------------------\n");
    // 循环读取每一行,直到 fgets 返回 NULL
    while (fgets(line, LINE_LENGTH, fp) != NULL) {
        // 去掉行尾的换行符
        size_t len = strlen(line);
        if (len > 0 && line[len - 1] == '\n') {
            line[len - 1] = '\0';
        }
        printf("%s\n", line);
    }
    // 关闭文件
    fclose(fp);
    return 0;
}

运行结果:

--------------------
床前明月光
疑是地上霜
举头望明月
低头思故乡

分析: while (fgets(line, LINE_LENGTH, fp) != NULL) 是逐行读取文件的经典模式,循环会一直持续,直到 fgets 到达文件末尾并返回 NULL,此时循环自动终止。

fgetsgets 的对比

在 C11 标准之前,还有一个函数叫 gets,但它极其危险,已经被标准弃用,并在 C11 中移除

特性 fgets gets (已弃用)
安全性 安全,可以指定最大读取长度,防止缓冲区溢出。 极不安全,无法指定读取长度,总是读取直到遇到换行符,极易导致缓冲区溢出。
参数 3个:缓冲区地址、最大长度、输入流 1个:缓冲区地址
换行符 保留换行符 \n 在读取的字符串中。 丢弃换行符 \n
输入流 可以是 stdin、文件等任意流。 只能是标准输入 stdin

永远不要使用 gets 函数!请始终使用 fgets 来替代它。


fgets 是 C 语言中处理字符串输入的基石,无论是从键盘还是从文件读取,它都是首选函数。

  • 优点:

    • 安全可控: 通过 n 参数防止缓冲区溢出。
    • 功能强大: 既能从标准输入读取,也能从文件读取。
    • 行为明确: 总是以 \0 并保留换行符。
  • 注意事项:

    • 记得检查返回值是否为 NULL,以处理错误或文件结束的情况。
    • 如果不希望字符串末尾有换行符,需要手动去除。
    • 使用前,确保目标缓冲区(str)有足够的空间。

掌握 fgets 是编写健壮、安全 C 程序的重要一步。

-- 展开阅读全文 --
头像
织梦new article.gif是什么文件?
« 上一篇 昨天
dede中channel的含义与作用是什么?
下一篇 » 今天

相关文章

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

目录[+]