使用堆内存读取文件后缓冲区无有效数据的问题求助
问题分析与解决:fread写入堆内存后数据无效
问题根源
你的代码核心问题出在参数传递错误:
- 在
main中,你把buffer指针的地址((char**)&buffer)传给了File::Read的void* buf参数。 - 而
File::Read里直接把buf传给fread,相当于把文件内容写入了buffer这个指针变量本身的内存空间(而非buffer指向的堆内存),这就导致后续访问buffer指向的堆内存时,里面仍是垃圾数据。 - 另外,
File::Read内部重新计算的fileSize可能和main中File.Tell()获取的filesize不一致,也可能引发数据读取不完整的问题。
解决方案
你不需要在File::Read里重新分配内存,只需要修正参数传递和函数参数的匹配:
方案1:修改File::Read的参数为直接接收数据缓冲区指针
调整Read函数的参数类型,让它直接接收你在main中分配好的堆内存指针:
// 修改File类的Read函数声明 size_t File::Read(char* buf, size_t bufSize) { // 用传入的bufSize作为读取上限,避免缓冲区溢出 ::fseek(fStream, 0, SEEK_END); int fileSize = ::ftell(fStream); ::fseek(fStream, 0, SEEK_SET); // 取文件大小和缓冲区大小的最小值,防止溢出 size_t readSize = std::min(static_cast<size_t>(fileSize), bufSize); ::fread(buf, 1, readSize, fStream); return readSize; } // main中调用方式修改为 int main(...) { MyFile File; File.Open(...); int filesize = File.Tell(); char* buffer = new char[filesize]; // 直接传buffer指针,同时传入缓冲区大小 File.Read(buffer, filesize); // 现在buffer里就是有效数据了 File.Close(); delete [] buffer; }
方案2:如果要保留void*参数(不推荐,类型不安全)
如果一定要用void*作为参数,那么main中直接传递buffer即可,不需要传二级指针:
size_t File::Read(void* buf, size_t bufSize) { ::fseek(fStream, 0, SEEK_END); int fileSize = ::ftell(fStream); ::fseek(fStream, 0, SEEK_SET); size_t readSize = std::min(static_cast<size_t>(fileSize), bufSize); ::fread(buf, 1, readSize, fStream); return readSize; } // main中调用 File.Read(buffer, filesize);
额外注意事项
- 永远要考虑缓冲区溢出问题,不要直接用文件大小作为读取长度,要和缓冲区大小做比较。
ftell返回的是long类型,强转成size_t时要注意溢出风险。- 如果你的
File::Tell()已经能正确获取文件大小,File::Read里可以直接使用传入的bufSize,不需要重复计算文件大小,减少IO操作。
内容的提问来源于stack exchange,提问作者Ariana_N
相关产品推荐
相关产品推荐

