使用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
相关产品推荐
相关产品推荐

