You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用sprintf生成文件名时buffer数组值意外变更的技术问询

问题分析与解决方案

嘿,我立刻就发现了导致你buffer被篡改的核心问题——你的name数组长度严重不足!

为什么buffer会被修改?

你定义了char name[1];,但sprintf(name, "%03i.jpg", pictures)生成的字符串至少需要8个字节的空间:比如000.jpg是7个可见字符,再加上C字符串必须的终止符\0,总共需要8字节。

sprintf不会检查目标数组的大小,它会直接往内存里写数据。当name的空间不够时,溢出的字节就会覆盖栈上相邻的变量。刚好你的buffer数组和name在栈上是相邻的(栈内存通常是向下增长的),所以溢出的字符串就直接把buffer的前几个字节给改写了——这就是为什么调用sprintf后buffer的前四个字节变成了0x30('0')、0x30('0')、0x2e('.')、0x6a('j'),刚好对应00.jpg的前几个字符。

修复步骤

  1. 扩大name数组的容量:
    把char name[1];改成足够容纳文件名的大小,比如char name[16];(足够应对更长的文件名,留有余量更安全)。

  2. 补充文件操作的错误检查:
    你的代码没有检查fopen是否成功(比如输入文件不存在的情况),也没有检查fread的返回值,这会导致程序在异常情况下崩溃。建议加上这些判断。

  3. 优化循环逻辑:
    原循环条件while (pictures < 50)不够严谨,应该结合fread的返回值判断是否读到文件末尾,避免无效循环。

修正后的代码

#include <stdio.h>
#include <stdint.h>

typedef uint8_t BYTE;

int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Usage: %s <input file>\n", argv[0]);
        return 1;
    }

    BYTE buffer[512];
    // 扩大name数组容量,足够容纳"%03i.jpg"格式的字符串
    char name[16];
    int pictures = 0;
    char *infile = argv[1];
    FILE *card = fopen(infile, "r");
    if (card == NULL) {
        printf("Could not open file %s\n", infile);
        return 1;
    }

    FILE *imagen = NULL;
    size_t bytes_read;
    while ((bytes_read = fread(buffer, sizeof(BYTE), 512, card)) > 0 && pictures < 50) {
        // 检查是否是JPEG的起始标志
        if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0) {
            if (pictures > 0) {
                fclose(imagen);
            }
            // 生成文件名(更安全的方式可以用snprintf)
            sprintf(name, "%03i.jpg", pictures);
            imagen = fopen(name, "w");
            if (imagen == NULL) {
                printf("Could not create file %s\n", name);
                fclose(card);
                return 1;
            }
            pictures++;
        }
        // 如果已经打开了图片文件,写入当前buffer
        if (imagen != NULL) {
            fwrite(buffer, sizeof(BYTE), bytes_read, imagen);
        }
    }

    // 关闭最后一个打开的图片文件
    if (imagen != NULL) {
        fclose(imagen);
    }
    fclose(card);
    return 0;
}

额外说明

  • 更安全的字符串格式化可以用snprintf,它能指定最大写入字节数彻底避免溢出:snprintf(name, sizeof(name), "%03i.jpg", pictures);
  • 注意fwrite的时候要写入实际读到的字节数(bytes_read),而不是固定的512,因为文件最后一段可能不足512字节。

内容的提问来源于stack exchange,提问作者David

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 15:42:40