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

网站首页 > 文章精选 正文

C语言fputs函数详解:“字符信件邮递员”

balukai 2025-03-26 09:42:27 文章精选 5 ℃

一句话理解 fputs

「将字符串像‘信件’一样完整投递到文件或屏幕,但不会偷偷塞入‘信封封条’(换行符)!」


函数原型

#include 
int fputs(const char *str, FILE *stream);

入口参数

参数

类型

比喻解释

str

const char*

要投递的「信件内容」(字符串)

stream

FILE*

信件的「目的地」(文件/屏幕)

返回参数

返回值

含义

非负数

投递成功(返回写入的字符数,不保证)

EOF

投递失败(如磁盘满/文件未打开)


核心功能图解

const char *msg = "Hello World";  
fputs(msg, stdout);  → 屏幕显示:Hello World  
fputs(msg, file);    → 文件内容:Hello World

代码实例:信件投递实战

场景1:创建日志文件(自动追加时间戳)

#include 
#include 

void log_message(const char *text) {
    FILE *log = fopen("app.log", "a");  // 追加模式打开日志
    if (!log) {
        perror(" 日志本打不开");
        return;
    }

    // 获取时间戳
    time_t now = time(NULL);
    struct tm *t = localtime(&now);
    char timestamp[20];
    strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", t);

    // 写入日志(格式:时间 + 信息)
    fputs("[", log);
    fputs(timestamp, log);
    fputs("] ", log);
    fputs(text, log);
    fputs("\n", log);  // 手动换行

    fclose(log);
}

int main() {
    log_message("程序启动成功");
    log_message("用户Alice登录系统");
    return 0;
}

日志文件内容

[2023-10-05 14:30:00] 程序启动成功  
[2023-10-05 14:30:02] 用户Alice登录系统

场景2:实现终端进度条(无换行特性)

#include 
#include   // 用于sleep

int main() {
    for (int i = 0; i <= 100; i += 10) {
        printf("进度:");          // printf自带缓冲区
        fputs("[", stdout);       // 直接输出左括号
        for (int j = 0; j < i/10; j++) {
            fputs("█", stdout);  // 用方块填充进度
        }
        fprintf(stdout, "] %d%%\r", i);  // \r回到行首
        fflush(stdout);          // 强制刷新显示
        sleep(1);
    }
    return 0;
}

动态效果

进度:[██████████] 100% (动态增长)

场景3:文件内容合并工具

#include 

void merge_files(const char *file1, const char *file2, const char *output) {
    FILE *f1 = fopen(file1, "r");
    FILE *f2 = fopen(file2, "r");
    FILE *out = fopen(output, "w");
    if (!f1 || !f2 || !out) {
        perror("文件打开失败");
        return;
    }

    char buffer[1024];
    // 合并第一个文件
    while (fgets(buffer, sizeof(buffer), f1) {
        fputs(buffer, out);
    }
    // 合并第二个文件
    while (fgets(buffer, sizeof(buffer), f2) {
        fputs(buffer, out);
    }

    fclose(f1);
    fclose(f2);
    fclose(out);
}

int main() {
    merge_files("part1.txt", "part2.txt", "complete.txt");
    return 0;
}

技术细节剖析

1. 与 puts 的致命差异

特性

fputs

puts

换行符处理

不自动添加换行符

自动添加换行符

输出目标

任意文件流

只能输出到stdout

性能

更高(无格式解析)

稍低(隐含换行操作)

2. 缓冲区安全规则

  • 必须确保字符串以\0结尾
char unsafe[3] = {'A', 'B', 'C'}; // 没有结束符! 
fputs(unsafe, file); //  内存越界读取!

死亡陷阱:常见错误

1. 误用未初始化的指针

char *msg;  // 未初始化!
fputs(msg, stdout);  //  随机内存地址,程序崩溃!

2. 忽略返回值导致数据丢失

// 危险!不检查是否写入成功
fputs("重要数据", file);  

// 安全写法:
if (fputs("重要数据", file) == EOF) {
    perror("数据写入失败");
}

高级技巧:实现二进制协议封装

#include 

void send_packet(FILE *network, const char *data, int length) {
    // 协议头:4字节长度标识
    char header[4];
    header[0] = (length >> 24) & 0xFF;
    header[1] = (length >> 16) & 0xFF;
    header[2] = (length >> 8)  & 0xFF;
    header[3] = length & 0xFF;
    
    fputs(header, network);    // 写入头部
    fputs(data, network);      // 写入数据
    fflush(network);           // 强制发送
}

int main() {
    // 模拟网络套接字
    FILE *socket = fopen("network.bin", "wb");
    send_packet(socket, "Hello Protocol!", 15);
    fclose(socket);
    return 0;
}

总结表格

特性

说明

核心优势

高效写入完整字符串

典型用途

日志记录、协议传输、数据拼接

安全准则

检查返回值,确保字符串合法


总结

  • 像邮差投递信件:fputs 是C语言中最直接的字符串输出工具,专注于完整内容传递。
  • 关键特性
    1 不添加额外换行符 → 精确控制输出格式
    2 支持任意文件流 → 灵活选择输出目标
    3 高性能无格式解析 → 效率碾压fprintf
  • 安全口诀
    「查地址(文件指针)、验内容(字符串)、盯回执(返回值)」
最近发表
标签列表