程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

C语言fgets函数详解:“安全数据搬运工”

balukai 2025-03-26 09:42:06 文章精选 6 ℃

一句话理解 fgets

「从文件或输入流中,安全搬运一行‘包裹’(字符串)到指定‘集装箱’(缓冲区),避免超载(溢出)!」


函数原型

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

入口参数

参数

类型

比喻解释

str

char*

存放数据的「集装箱」(字符数组)

n

int

集装箱的最大容量(含结尾\0)

stream

FILE*

货物的「传送带」(文件指针)

返回参数

返回值

含义

char*

成功返回 str 指针

NULL

货物已搬完(文件尾)或搬运失败


核心功能图解

传送带上的货物:H e l l o  W o r l d 
调用 fgets(buf, 10, file) → 第一次搬运:"Hello\n\0",第二次搬运:"World\n\0"

代码实例:安全搬运实战

场景1:从键盘读取用户输入(防溢出)

#include 

int main() {
    char name[20];  // 集装箱容量:20字符(含\0)
    printf("请输入你的名字(最多19字符):");
    
    // 从键盘(stdin)安全搬运输入
    if (fgets(name, sizeof(name), stdin) != NULL) {
        // 去除末尾可能的换行符
        name[strcspn(name, "\n")] = '\0'; 
        printf("你好,%s!\n", name);
    } else {
        printf("输入失败!\n");
    }
    return 0;
}

输入测试

输入:Alice
输出:你好,Alice!

场景2:逐行读取文件内容

#include 

int main() {
    FILE *file = fopen("diary.txt", "r");
    if (!file) {
        perror(" 日记本打不开");
        return 1;
    }

    char line[100];  // 集装箱容量:100字符
    int line_num = 1;

    // 逐行安全搬运,直到文件尾
    while (fgets(line, sizeof(line), file) != NULL) {
        printf("行%02d:%s", line_num, line);
        line_num++;
    }

    fclose(file);
    return 0;
}

文件内容(diary.txt):

2023-10-05 晴
今天学会了fgets函数!

输出

行01:2023-10-05 晴
行02:今天学会了fgets函数!

常见错误与注意事项

1.未处理换行符

char buf[10];
fgets(buf, 10, stdin);
printf("输入内容:%s", buf);  // 若输入"Hello",输出"Hello\n"
// 正确做法:替换换行符(如场景1)

2.误用 sizeof 和 strlen

char buf[20];
// 错误!sizeof(buf)返回20,但若buf是动态分配的指针,会出错
fgets(buf, sizeof(buf), stdin); 

// 正确做法(动态数组):
char *buf = malloc(20);
fgets(buf, 20, stdin);  // 直接写数字

3.忽略返回值检查

char buf[100];
fgets(buf, 100, file);  //  不检查返回值,可能读到NULL
// 正确写法:if (fgets(...)) { ... }

技术细节剖析

1.与 gets 的致命区别

特性

fgets

gets(已废弃)

安全性

明确指定缓冲区大小

可能溢出缓冲区

保留换行符

保留并存入缓冲区

丢弃换行符

推荐程度

必须使用

绝对禁止使用

2.精准的字符搬运量

char buf[5];
fgets(buf, 5, file);  // 最多搬运4字符+1个\0
  • 输入"Hello" → 搬运"Hell\0"(截断剩余字符)
  • 输入"Hi" → 搬运"Hi\n\0"

高级技巧:实现 cat 命令

#include 

void print_file(FILE *file) {
    char buffer[1024];
    while (fgets(buffer, sizeof(buffer), file) != NULL) {
        fputs(buffer, stdout);  // 等效于printf("%s", buffer)
    }
}

int main(int argc, char **argv) {
    if (argc == 1) {
        // 无参数时,从stdin读取
        print_file(stdin);
    } else {
        // 有参数时,逐个打开文件
        for (int i = 1; i < argc; i++) {
            FILE *file = fopen(argv[i], "r");
            if (file) {
                print_file(file);
                fclose(file);
            } else {
                fprintf(stderr, "无法打开文件:%s\n", argv[i]);
            }
        }
    }
    return 0;
}

总结表格

特性

说明

安全性

防缓冲区溢出

换行处理

保留换行符并存入缓冲区

适用场景

逐行读取文件、安全输入

性能

适合文本处理,不建议二进制流


总结

  • 核心功能:安全读取字符串,防止缓冲区溢出
  • 必用场景:处理用户输入、逐行读取文件、网络数据流
  • 类比记忆:就像智能物流机器人,fgets 是程序员安全搬运字符串的「防溢出卫士」
最近发表
标签列表