使用字符串实现fread()和fwrite()时遇崩溃及读取失败问题求助
问题分析与解决方法
核心错误原因
你的代码存在两个致命问题,直接触发内存错误:
- 错误读写std::string对象本身:
std::string是包含内部指针、长度、容量的复合对象,sizeof(value)获取的是该对象的内存大小(通常12或24字节,取决于平台),而非字符串内容的长度。你写入文件的是string的内部结构(比如指向堆内存的指针),而非"abcd"本身;读取时直接覆盖retrieved对象的内存,会破坏其内部指针,析构时触发free(): invalid pointer或段错误。 - 空string越界访问:
当retrieved是空字符串时,retrieved[0]属于未定义行为——空string没有可访问的字符元素,无法通过这种方式写入数据。
正确实现方式
要正确读写std::string的内容,需要先写入字符串的长度(或写入带终止符的内容),再写入实际字符;读取时先获取长度,再分配足够空间读取内容。以下是可靠的实现:
修正后的代码
#include <cstdio> #include <string> #include <iostream> static bool file_read(FILE* file) { std::string value = "abcd"; std::string retrieved; // 写入字符串:先写长度,再写内容 const size_t len = value.size(); fwrite(&len, sizeof(len), 1, file); fwrite(value.data(), sizeof(char), len, file); // 回到文件开头 fseek(file, 0, SEEK_SET); // 读取字符串:先读长度,再分配空间读内容 size_t read_len; fread(&read_len, sizeof(read_len), 1, file); retrieved.resize(read_len); // 为读取内容分配足够空间 fread(retrieved.data(), sizeof(char), read_len, file); // 验证结果 std::cout << "读取到的字符串:" << retrieved << std::endl; return true; } int main(int argc, char *argv[]) { FILE *file = fopen("file_test", "wb+"); if (!file) { std::cerr << "文件打开失败" << std::endl; return 1; } file_read(file); fclose(file); return 0; }
关键步骤说明
- 写入逻辑:
- 先写入字符串的长度,确保读取时知道需要分配多少内存。
- 使用
value.data()获取字符串内容的指针,写入实际的字符数据(value.c_str()也可,但data()更适合写入操作)。
- 读取逻辑:
- 先读取之前写入的长度值。
- 调用
retrieved.resize(read_len)为字符串分配足够的内存空间。 - 读取字符数据到
retrieved.data()指向的内存区域。
可选方案:写入带终止符的字符串
如果你的字符串不包含\0字符,也可以写入带终止符的内容,读取时直接转为string:
// 写入 fwrite(value.c_str(), sizeof(char), value.size() + 1, file); // 读取 char buffer[1024]; fread(buffer, sizeof(char), sizeof(buffer), file); retrieved = buffer;
这种方式更简单,但无法处理包含\0的字符串,可靠性不如长度前缀的方式。
内容的提问来源于stack exchange,提问作者Yunho Jin
相关产品推荐
相关产品推荐

