C++:使用嵌套 if/else 语句对 while 循环进行故障排除

C++: Troubleshooting while loop with nested if/else statement

我正在学习 C++,有几个问题。

此程序应输入商品的名称和价格并将其输出到文本文件。当为项目名称输入标记值 999 时,while 循环应停止并将所有输入集(项目名称和价格)输出到文本文件。

这个程序有两个问题:

  1. 仅显示最新的一组输入(名称、价格)。如何将所有输入保存在内存中?

  2. 为项目名称输入 999 不会导致程序退出。相反,程序不再显示提示。如何正确停止程序?

我可能应该使用 for 循环,但我不确定它是如何实现的。

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

using namespace std;

int main()
{
    string item_name;
    double price;
    int item_number;

    const string SENTINEL = "999";

    ofstream myfile ("invoice1.txt");


    while(item_name != SENTINEL)
    {
        cout<<"Enter the name of the item."<<'\n';
        cin>>item_name;

        if (item_name == SENTINEL)
        {
            cin>>item_name;
            myfile<<"Thank you for your entries"<<'\n';
            myfile<<item_name<<"#"<<price<<endl;
            myfile.close();

            break;
        }
        else
        {
            cout<<"Enter the price of the item."<<'\n';
            cin>>price;
        }
    }

    myfile<<"Thank you for your entries"<<'\n';
    myfile<<item_name<<"#"<<price<<endl;
    myfile.close();

    return 0;
}

为什么在检查条目的 if 语句中有一个额外的 cin 调用? 我觉得没必要。

对于您输入的问题,您只存储了最近输入的值,因为每次循环 运行s 再次它会覆盖变量。

要解决这个问题,您需要使用数组来存储项目。如果你想做到这样你就可以 运行 循环并根据需要输入尽可能多的输入,你将需要实现一个动态数组。

下面是动态数组的实现方法http://www.learncpp.com/cpp-tutorial/6-9a-dynamically-allocating-arrays/

如何使用 std::vector

首先,有几个包括:

#include <vector> // obviously. Can't do vectors without the vector header.
#include <limits> // for a trick I'll use later

创建结构 link 商品名称和价格

struct item
{
    string name;
    double price;
};

并制作该结构的向量

vector<item> items;

然后在读入名称和价格后,将其填充到一个结构中并将该结构填充到向量中。

item temp;
temp.name = item_name;
temp.price = price;
items.push_back(temp);

为什么 while 循环不起作用...这需要走一走。

while(item_name != SENTINEL)

这是一个好的开始。如果 item_name 不是 SENTINEL,请继续。非常正确。问题是,您第一次到达此处时尚未设置 item-name,从而在循环中强制执行了一些松鼠逻辑。阅读一般经验法则,然后进行测试。阅读前测试不是很有用。一方面,没有什么可测试的,但真正的问题是现在您正在使用未经测试的数据,或者必须包括另一个测试来捕获它。

阅读,然后测试。

{
    cout<<"Enter the name of the item."<<'\n';
    cin>>item_name;

获取项目名称。 Groovy-ish.

    if (item_name == SENTINEL)
    {
        cin>>item_name;

好的。还不错,但为什么要在这里得到另一个 item_name?

        myfile<<"Thank you for your entries"<<'\n';
        myfile<<item_name<<"#"<<price<<endl;
        myfile.close();

        break;

break 退出循环或 switch。所以我们走了。

    }
    else
    {
        cout<<"Enter the price of the item."<<'\n';
        cin>>price;

读取数值有一些您必须注意的危险。最重要的是,如果用户键入的任何内容都不能变成 pricecin 就会进入错误模式,并且在清除错误之前不会退出。在您尝试再次获取价格之前,需要删除垃圾数据。

cin >> x 的巧妙之处在于 returns cin。这使您可以堆叠命令。 cin>>a>>b>>c>>dcin 及其所有流媒体兄弟都有一个内置的布尔运算符,您可以在测试中使用。如果cin状态还不错,所有读取都成功完成,可以测试,会returntrue.

这让您可以执行 if (cin>>a>>b>>c>>d) 之类的操作,并一次测试所有读取是否良好。

    }
}

应用读取,然后测试,我们得到

while(cin>>item_name && // read in an item name
      item_name != SENTINEL) // and then test that it isn't the sentinel

这段看似愚蠢的代码是执行此操作的最安全方法。它甚至会捕获并退出 cin 突然结束。 cin 不会经常发生,但这是测试文件结尾的好方法。

{
    while (!(cin >> price)) // keep looping until the user gives a number
    {  // if we're here, the user didn't give a good number and we have to clean up 
       // after them. Bad user. Bad. Bad.

顺便说一句,不要用文件做这个把戏。该文件可能已经结束。在继续清理之前,您必须在文件末尾测试文件并在此处退出。

        // clear the error
        cin.clear(); 
        // throw out everything the user's typed in up to the next line
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }
    // user got out of the while of doom. They must have entered a number.

实际上,它只需要以数字开头。 cin >> 非常愚蠢,它会让 1234abcd 通过,取走 1234 并将 abcd 留给下一次读取。这可能会给您带来一些令人讨厌的惊喜。在这种情况下,abcd 将作为下一个 item_name 结束。本来应该是下一个 item_name 的将成为下一个 price,糟糕的 ju-ju 从那里开始。

现在回到代码。

    item temp; // make a temporary item
    temp.name = item_name; // set the values correctly
    temp.price = price;
    items.push_back(temp); // put them in the list.

您可以通过向 item 添加构造函数并使用 vectoremplace_back 方法来节省一些工作。查一下。非常好用。

}

同样没有 运行 评论:

while(cin>>item_name && // read in an item name
      item_name != SENTINEL) // and then test that it isn't the sentinel
{
    while (!(cin >> price)) // keep looping until the user gives a number
    {  // if we're here, the user didn't give a good number and we have to clean up 
       // after them. Bad user. Bad. Bad.
        // clear the error
        cin.clear(); 
        // throw out everything the user's typed in up to the next line
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }
    // user got out of the while of doom. They must have entered a number.
    item temp; // make a temporary item
    temp.name = item_name; // set the values correctly
    temp.price = price;
    items.push_back(temp); // put them in the list.
}

现在您有 vectoritem 份要打印。 Stack Overflow 上有很多关于如何执行此操作的示例,但最好先尝试一下。