使用分隔符将文本文件读入结构体数组的C++代码

3

我将尝试从一个格式类似于以下内容的文本文件中读取数据:

knife, object, 0
bag, object, 15
kitchen, room, 400

将数据存储到由结构体组成的数组中。以下是我目前的代码,但它只读取第一个元素,然后返回垃圾数据。

#include <iostream>
#include <fstream>
#include <string>


using namespace std;

struct itemlist
{
  string type;
  string selltype;
  int price;
  int diditsell=0;
};

int main()
{
  string filename;
  cout << "Please enter a file name. " << endl;
  cin >> filename;

  ifstream in(filename);
  itemlist c[100];
  for (int i=0;i<100;i++)
  {
      in >> c[i].type >> c[i].selltype >> c[i].price;
      cout << c[i].type << endl;
      cout << c[i].selltype << endl;
      cout << c[i].price << endl;
  }
}

我已经尝试寻找与我尝试做的事情特别相符的示例,但实施它们并没有解决问题。非常感谢任何帮助。


检查读取是否成功:if (in >> c[i].type >> c[i].selltype >> c[i].price) { 打印内容; } else { 处理错误; } - user4581301
哦等等!你需要解析逗号和空格吗?呸。这需要使用 std::getline(in, c[i].type, ','); 然后再加上一些额外的代码来分离空格。 - user4581301
如果文件中的数量少于100个,您不想读取全部100个。您可以使用std::vector吗? - user4581301
@user4581301 我被指示创建大小为100的对象。使用std::vector似乎没有任何问题,但我的C++技能不是很熟练。 - Nick Bearns
2个回答

1
可见问题的关键在于


 for (int i=0;i<100;i++)

整个100元素数组将被打印出来,无论文件中是否有数据加载到数组中。
可能最简单的方法是使用std::vector。它是一个动态大小的数组。当您向其添加内容时,它会变得更大,因此您不必担心它溢出。我们在最后回到它。
接下来,您需要确保成功读取文件。可以测试流以查看其是否有效
if (in)
{
    cout << "in is good!" << endl;
}

>> 运算符返回流的引用,因此您可以

if (in >> data)
{
    cout << "data is good!" << endl;
}

如果在读取数据后,流仍然良好,则至少知道文件将某些内容读入数据中,这些内容是正确类型或可以转换为正确类型的。您需要检查读取的值以确保用户没有输错或刻意使程序崩溃。如果您想循环遍历大量内容,例如文件,则最终会得到类似以下的内容:
while (in >> c[i].type >> c[i].selltype >> c[i].price)

如果任何读取操作失败,流在测试时将返回false,并退出循环。
从您的源数据中看,您需要处理空格和逗号。除非您要做很多额外的工作,否则>>只能处理空格。您将读取的内容是:
knife,
object,
0

我们不想要逗号。幸运的是,它是最后一个字符,所以处理起来很容易。 C++11 std::string 可以像栈一样使用,你可以弹出不需要的字符:

c[i].type.pop_back();
c[i].selltype.pop_back();

所有这些加在一起,就得到了以下循环:
ifstream in(filename);
itemlist c[100];
int i = 0;
while (in >> c[i].type >> c[i].selltype >> c[i].price)
{
    c[i].type.pop_back();
    c[i].selltype.pop_back();
    cout << c[i].type << endl;
    cout << c[i].selltype << endl;
    cout << c[i].price << endl;
    i++;
}

但是这可能会超出100个元素的数组的末尾,因此我们需要稍微改变while循环:

while (i < 100 && in >> c[i].type >> c[i].selltype >> c[i].price )

如果 i 大于等于 100,则 i < 100 的情况失败,循环退出,甚至不尝试执行 in >> c[i].type >> c[i].selltype >> c[i].price 并写入不存在的数组槽。
记得保留 i 的值,因为数组是愚蠢的。它们不知道自己有多满。
但使用 vector 时,您不需要 i 来计数或跟踪其填充状态,也不需要担心溢出数组,直到将计算机的 RAM 运行完毕。我们只需要一个临时变量来读取,就可以开始了。
vector<itemlist> c;
itemlist temp;
while (in >> temp.type >> temp.selltype >> temp.price)
{
    temp.type.pop_back();
    temp.selltype.pop_back();
    cout << temp.type << endl;
    cout << temp.selltype << endl;
    cout << temp.price << endl;
    c.push_back(temp);
}

非常感谢您的帮助。但我在这段代码上遇到了问题。我发现一旦编译和运行代码后,程序窗口中没有任何内容显示。由于使用了cout,它不应该显示一些东西吗?而且,如何调用这个数组呢?当我简单地调用:“cout << c[1].type << endl;”时,程序就会崩溃。有什么建议吗? - Nick Bearns
@NickBearns除了尝试使用开发环境的调试软件之外,我没有其他建议。调试器是非常方便的工具。当程序崩溃时,它应该会停止并允许您检查程序的状态。这将为您提供更多信息,以便解决问题或提出一个非常好的、有针对性的新问题。 - user4581301
我似乎找到了错误。我的文件中有一个条目:water, not object, 0问题源于第二个元素中单词之间的空格。这会在后面造成问题,因为使用in >> temp.type >> temp.selltype >> temp.price似乎将价格保存为单词“object”,但由于它不是整数,无法正确存储。 - Nick Bearns
@NickBearns 糟糕。如果您控制数据文件格式,可以禁止空格,但最好切换到std :: getline,以便正确处理双手剑。今晚出现了一个类似的问题,您应该能够适应。http://stackoverflow.com/a/41844212/4581301 - user4581301

0
我曾经遇到过同样的问题。 调试显示它读取了第一个数组元素,但跳过了第二个元素并输出了第一个元素的信息。 通过让它读取第一个元素两次来解决这个问题。 例如,请参见下面的代码。
数组中还有其他玩家输入。 添加了那行代码后,一切都很顺利。 我必须对每个我读取的数组都这样做。 我查看了它要读取的文本文件,果然在每个数组开始之前都有一个空行。 我不知道编写该文件的程序为什么要这样做。 注意:您可以让它读取一个空行,而不是读取第一个数组元素两次。
 for (int i = 0; i < PLAYER; i++)
    {
    getline(teamRosterIn, playerName[i]);
    cout << playerName[i] << endl;
    getline(teamRosterIn, playerName[i]);
    cout << playerName[i] << endl;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接