C++读取txt文件内容存入数组后仅输出最后一个元素问题排查
问题诱因
- 你存储的是
std::string line的内部数据指针line.data(),而整个循环过程中line是同一个被复用的对象,每次std::getline执行时都会覆盖line内部的缓冲区内容,你数组里存的所有指针都指向同一个内存地址,自然最后所有指针读到的都是最后一次写入的内容。 - 位置(1)打印正常是因为打印时当前循环的
line内容还没有被下一次getline覆盖,指向的内容是当前读取的行,循环结束后line最终存储的是文件最后一行,所以位置(2)遍历所有指针读到的都是最后一行。 - 额外说明:你混用了C的文件流和C的文件操作、裸指针,属于C和C语法混写,很容易出现这类内存管理问题。
解决方法
推荐使用更安全的纯C++风格实现,不需要手动管理内存:
将存储昵称的数组改为std::vector<std::string>,每次读取到line后直接存入容器,会自动完成内容拷贝,修改后参考代码如下:
#include <iostream> #include <fstream> #include <string> #include <vector> #include <cstdlib> #include <ctime> int main() { // 初始化随机种子,否则每次运行生成的随机结果相同 srand(time(nullptr)); std::vector<std::string> nicknames; std::string line; std::ifstream file("nicknames.txt"); FILE *fileID = fopen("asd.txt", "w"); while (std::getline(file, line)) { nicknames.push_back(line); // (1)位置打印 fprintf(fileID, "%i: %s\n", (int)nicknames.size() - 1, nicknames.back().c_str()); } int nicknameCount = nicknames.size(); int randomNickIndex = rand() % nicknameCount; // (2)位置遍历打印 for (int i = 0; i < nicknameCount; i++) { fprintf(fileID, "%i: %s\n", i, nicknames[i].c_str()); } fprintf(fileID, "Result: %s\n", nicknames[randomNickIndex].c_str()); fprintf(fileID, "Result: %i\n", randomNickIndex); fclose(fileID); return 0; }
如果一定要保留原有char*数组的实现方式,需要每次读取后手动拷贝内容到新申请的内存空间:
while (std::getline(file, line)) { // 申请新内存存储当前行内容,长度+1是为了存储字符串结束符'\0' char *cur_line = new char[line.size() + 1]; strcpy(cur_line, line.c_str()); nicknames[nicknameCount++] = cur_line; fprintf(fileID, "%i: %s\n", nicknameCount - 1, nicknames[nicknameCount - 1]); } // 注意:程序退出前需要遍历数组,对每个元素执行delete[]释放内存,避免内存泄漏
内容的提问来源于stack exchange,提问作者Random Dude
相关产品推荐
相关产品推荐

