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

使用32位int存储fread()读取的数据为何出现垃圾值?

问题解析:int缓冲区出现垃圾值,unsigned char正常的原因

这个问题的核心是数据类型的字节宽度、内存初始化状态,再加上你代码里对缓冲区的错误使用导致的,咱们一步步说清楚:

1. int和unsigned char的字节宽度差异

32位系统下,int类型占4字节,而unsigned char占1字节。你的代码里用fread(buffer, 1, BUFFER_SIZE, inputfile),意思是从文件读取BUFFER_SIZE个1字节的数据,然后依次写入buffer指向的内存。

  • 当buffer是int*类型时:你分配了BUFFER_SIZE * sizeof(int)字节的内存(也就是512*4=2048字节),但fread只写入了前512字节。剩下的2048-512=1536字节是malloc分配的未初始化内存,里面全是随机垃圾值。而你打印的是int类型的值,每个buffer[i]对应4字节的内存——其中只有1字节是文件读取的有效数据,另外3字节都是垃圾,所以打印出来的自然是垃圾值。
  • 当buffer是unsigned char*类型时:你分配的是BUFFER_SIZE * sizeof(unsigned char)=512字节的内存,fread刚好把这512字节全部填满,没有剩余的未初始化内存,所以每个元素都是文件里的有效数据,打印正常。

2. 原代码里的JPEG签名判断逻辑也是错误的

你可能没注意到,原代码里判断JPEG开头的buffer[0] == 0xff && buffer[1] == 0xd8...完全不符合预期:

  • 对于int*的buffer,buffer[0]指向的是4字节的int,而不是文件的第一个字节。比如文件前4字节是0xff 0xd8 0xff 0xe0,小端系统下buffer[0]的int值是0xe0ffd8ff,和0xff完全不相等,所以你的签名判断永远不会触发,根本没法正确识别JPEG文件头。
  • 换成unsigned char*后,buffer[0]就是文件的第一个字节,buffer[1]是第二个字节,以此类推,这时候签名判断才是正确的。

代码修正建议

把缓冲区类型改成unsigned char*,同时调整相关函数的参数,还补充了二进制文件写入和剩余数据处理的细节:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define BUFFER_SIZE 512
void print_array(unsigned char *array, int up_to);

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: ./recover filename\n");
        return 1;
    }
    FILE *inputfile = fopen(argv[1], "r");
    if (inputfile == NULL) {
        fprintf(stderr, "Cannot open specified file!\n");
        return 2;
    }
    FILE *outputfile = NULL;
    unsigned char *buffer = malloc(BUFFER_SIZE * sizeof(unsigned char));
    if (buffer == NULL) {
        printf("Not enough memory!\n");
        return 4;
    }
    int file_count = 0;
    size_t read_bytes;
    while ((read_bytes = fread(buffer, 1, BUFFER_SIZE, inputfile)) == BUFFER_SIZE) {
        print_array(buffer, 5);
        if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0) {
            if (outputfile != NULL) fclose(outputfile);
            char filename[8];
            sprintf(filename, "%03d.jpg", file_count);
            outputfile = fopen(filename, "wb"); // 用wb模式写二进制文件,避免换行转换
            file_count++;
        }
        if (outputfile != NULL) fwrite(buffer, 1, read_bytes, outputfile); // 按实际读取的字节数写入
    }
    // 处理最后一次读取的不足BUFFER_SIZE的字节
    if (outputfile != NULL && read_bytes > 0) {
        fwrite(buffer, 1, read_bytes, outputfile);
    }
    if (outputfile != NULL) fclose(outputfile);
    fclose(inputfile);
    free(buffer);
    return 0;
}

void print_array(unsigned char *array, int up_to) {
    for (int i = 0; i < up_to; i++)
        printf("element at index %i: 0x%02x (%u)\n", i, array[i], array[i]);
    printf("\n");
}

额外提两个小细节:

  • 写二进制文件时用wb模式,避免系统自动转换换行符(Windows下会把\n转成\r\n,破坏JPEG的二进制结构)。
  • 要处理最后一次读取不足BUFFER_SIZE的情况,避免遗漏数据。

内容的提问来源于stack exchange,提问作者Bagas Wahyu Hidayah

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:49:15