为什么我的程序出错了?c++

时间:2021-06-11 22:45:08

I have a program for my c++ class that for some reason keeps breaking when I get to a certain point in my program.

我有一个c++类的程序,由于某些原因,当我在程序中到达某个点时,它会一直中断。

Here is the header file of my

这是我的头文件。

// This class has overloaded constructors.
#ifndef INVENTORYITEM_H
#define INVENTORYITEM_H
#include <string>
using namespace std;

class InventoryItem
{
private:
   string description; // The item description
   double cost;        // The item cost
   int units;          // Number of units on hand
   int inventoryItemNumber; //Used to sort items from first entered to last
public:
   // Constructor #1
   InventoryItem()
      { // Initialize description, cost, and units.
        description = "";
        cost = 0.0;
        units = 0; }

   // Constructor #2
   InventoryItem(string desc)
      { // Assign the value to description.
        description = desc;

        // Initialize cost and units.
        cost = 0.0;
        units = 0; }

   // Constructor #3
   InventoryItem(string desc, double c, int u)
      { // Assign values to description, cost, and units.
        description = desc;
        cost = c;
        units = u; }

   // Mutator functions
   void setDescription(string d) 
      { description = d; }

   void setCost(double c)
      { cost = c; }

   void setUnits(int u)
      { units = u; }

   // Accessor functions
   string getDescription() const
      { return description; }

   double getCost() const
      { return cost; }

   int getUnits() const
      { return units; }
};
#endif

And this is my cpp file containing my main:

这是我的cpp文件,包含了我的主要内容:

#include "InventoryItem.h"
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;

int main(){

    InventoryItem item[1000];
    string parsingArray[1000];
    char command;
    ifstream inFile;
    string inFileName;
    //The typecasting variables from string to int,string,double,int

    //other possible integers ROUND 2
    int itemNumber;
    string description;
    double cost;
    int units;

    //possible variables:
    int count = 0;
    int jTracker = 0;
    string parsingArray2[1000];

    while(true){
        cout << "Command: ";
        cin  >> command; cin.ignore(80, '\n');

        if (command == 'a') {
            //Add parts: increase the units value for an existing inventory item.
        }
        else if (command == 'h') {
            //Prints Help Text
            cout << "Supported commands: \n"
                << "                 a    Add parts.\n"
                << "                 h    print Help text.\n"
                << "                 i    Input inventory data from a file.\n"
                << "                 p    Print invetory list.\n"
                << "                 n    New invetory Item.\n"
                << "                 o    Output invetory data to a file.\n"
                << "                 q    quit (end the program).\n"
                << "                 r    Remove Parts.\n"
                << endl;
        }
        else if (command == 'i') {
            //Input inventory data from a file.
            do{
                cout << "Enter name of input file: ";
                getline(cin, inFileName);
                inFile.open(inFileName);
                if (inFile.fail())
                {

                    cout << "Failed to open file: " << inFileName << "\n\n";

                }
            }while(inFile.fail());

            //write each line to string
            for (int i = 0; inFile; i++) {
                getline(inFile, parsingArray[i], '\n');
                count++;//count will be needed for counting iterations of for loop for InventoryItem object data field completion
            }

            for (int k = 0; k < count; k++)
            {
                int newLine = 0;
                int num = 0;
                int oldDelimiter = 0, newDelimiter = 0;
                int variable = 0;

                for (int j = jTracker; num < variable; j++) {//jTracker continues to grow through multiple outer "k" loops.
                    newDelimiter = parsingArray[k].find("|", oldDelimiter);      //newDelimiter becomes the further pipe delimiter in the line.
                    parsingArray2[j] = parsingArray[k].substr(oldDelimiter, ((newDelimiter)-oldDelimiter));//the pipe delimited strings are isolated in input2[]
                    oldDelimiter = newDelimiter + 1;//oldDelimiter is set to the next pipe delimiter.


                    variable = parsingArray[k].length();
                    //The following alters variables as needed for the next loop
                    num = newDelimiter;
                    jTracker = (j + 1);
                    newLine = j;
                }
            }


            for(int y = 0; y < count; y++)
            {
                int itemNumber = stoi(parsingArray2[0+(4*y)]);
                string description = parsingArray2[1+(4*y)];
                double costs = stof(parsingArray2[2+(4*y)]);
                int unit = stoi(parsingArray2[3+(4*y)]);
                item[itemNumber].setDescription(description);
                item[itemNumber].setCost(costs);
                item[itemNumber].setUnits(unit);
            }

            cout << count << " records loaded to array.\n";

        }
        else if (command == 'p') {

        }
        else if (command == 'j') {

        }
        else if (command == 'o') {

        }   
        else if (command == 'q') {
            // Quit.
            cout << "Exit." << endl;
            system("pause");
            return 0;
        }
        else if (command == 'r') {

        }
        else {
            // Invalid user input, re-prompted.
            cout << "Invalid command.\n";
        }

    }
}

The assignment was to create a program that does all the actions described in the help menu. I started with "i" which is to input text files' information into an array of InventoryItem onjects, containing description of item, cost of item and total number of item units. Also, inventoryitem # should be included, but the array spot held by the object is the same as the item number, so a variable isn't needed.

任务是创建一个程序,它执行help菜单中描述的所有操作。我从“I”开始,即将文本文件的信息输入到InventoryItem的数组中,其中包含项目的描述、项目的成本和项目单元的总数。此外,还应该包括inventoryitem #,但是对象所持有的数组位置与项目号相同,因此不需要变量。

I try running the program, it runs. I type in "i" as my command. It asks for a file to input, I use the file "plumbing.txt". Plumbing.txt contains the following pipe-delimited text:

我尝试运行程序,它运行。我输入“I”作为我的命令。它要求一个文件输入,我使用文件“plumb.txt”。管道。txt包含以下的管道分隔文本:

0|Pump|39.00|20
1|Gasket|1.50|29
2|Water Level Gauge|12.99|30
3|Faucet Repair Kit|4.89|8
4|Teflon Thread Seal Tape (50 ft roll)|3.30|12
5|shutoff valve|6.50|10

Once i hit enter after typing in "plumbing.txt", the program programs.

有一次,我输入“管道”后输入了输入。txt”,该项目计划。

It looks like this:

它看起来像这样:

"command: i

“我命令:

Enter file name for input: plumbing.txt" And then the program breaks.

输入文件名称:管道。然后程序中断。

I narrowed down the part of the code to what actually causes the program to break and its something in this part of the code:

我把代码的一部分缩小到实际上导致程序崩溃的部分在代码的这部分中:

for(int y = 0; y < count; y++)
            {
                int itemNumber = stoi(parsingArray2[0+(4*y)]);
                string description = parsingArray2[1+(4*y)];
                double costs = stof(parsingArray2[2+(4*y)]);
                int unit = stoi(parsingArray2[3+(4*y)]);
                item[itemNumber].setDescription(description);
                item[itemNumber].setCost(costs);
                item[itemNumber].setUnits(unit);
            }

Please help me figure out why my program keeps breaking. I cannot figure it out. I'm trying to read the input as strings from the file, parse the strings into individual pieces of data. Convert from string to integer or double using stoi or stof and enter the info into the array of objects. Thank you for reading and any help you can offer.

请帮我弄清楚为什么我的程序老是坏。我想不出来。我尝试从文件中读取输入作为字符串,将字符串解析为单个数据块。使用stoi或stof将字符串转换为整数或double,并将信息输入到对象数组中。感谢您的阅读和任何帮助。

1 个解决方案

#1


0  

There are two issues with your code involving the use of for loops when it is better to use while. The first issue involves the block of code:

您的代码中有两个问题涉及到在使用时使用for循环。第一个问题涉及到代码块:

for (int i = 0; inFile; i++) {
    getline(inFile, parsingArray[i], '\n');
    count++;//count will be needed for counting iterations of for loop for InventoryItem object data field completion
}

Here, count is incremented even after we have reached the end of the file. As a result, count will be one more than the number of lines in the file. We can use a while loop instead:

在这里,即使我们已经到达文件的末尾,计数仍然是递增的。因此,count将比文件中的行数多一个。我们可以用while循环来代替:

while (getline(inFile, parsingArray[count], '\n')) 
  ++count;

Here, getline will set the end-of-file flag for the inFile ifstream when the last line is read so that the while loop exits. With count initialized to zero before this while loop, the resulting count will correctly reflect the number of lines in the file.

在这里,getline将在最后一行读取时为inFile ifstream设置文件结束标志,以便while循环退出。在此while循环之前,将count初始化为零,结果计数将正确地反映文件中的行数。

The second issue involves the block of code:

第二个问题涉及代码块:

for (int j = jTracker; num < variable; j++) {//jTracker continues to grow through multiple outer "k" loops.
    newDelimiter = parsingArray[k].find("|", oldDelimiter);      //newDelimiter becomes the further pipe delimiter in the line.
    parsingArray2[j] = parsingArray[k].substr(oldDelimiter, ((newDelimiter)-oldDelimiter));//the pipe delimited strings are isolated in input2[]
    oldDelimiter = newDelimiter + 1;//oldDelimiter is set to the next pipe delimiter.


    variable = parsingArray[k].length();
    //The following alters variables as needed for the next loop
    num = newDelimiter;
    jTracker = (j + 1);
    newLine = j;
}

As pointed out by others, num and variable are both set to zero before this for loop so that the condition num < variable is never met. Therefore, the code within the for loop is never executed. Again, a while loop here will do:

正如其他人指出的那样,num和变量在循环之前都被设置为0,这样就不会满足条件num <变量。因此,for循环中的代码永远不会被执行。再一次,这里的while循环将会:< p>

while ((newDelimiter = parsingArray[k].find("|", oldDelimiter)) != std::string::npos) {
    parsingArray2[j] = parsingArray[k].substr(oldDelimiter, ((newDelimiter)-oldDelimiter)); //the pipe delimited strings are isolated in input2[]
    oldDelimiter = newDelimiter + 1; //oldDelimiter is set to the next pipe delimiter.
    ++j; // increment j
}
// get the last token and increment j
parsingArray2[j] = parsingArray[k].substr(oldDelimiter, std::string::npos); //the pipe delimited strings are isolated in input2[]
++j;

Here, find will return std::string::npos if there are no more delimiters (i.e., "|") to find. With j initialized to zero before the outer k for loop, this while loop will parse all tokens delimited by "|" except for the last one. Therefore, after the while loop, we extract the last substring using std::string::npos to denote that we want all characters from oldDelimiter until the end of the string. Note that the variables newLine, num, variable, and jTracker are all not needed.

这里,find将返回std::字符串::npos,如果没有更多的分隔符(也就是。“|”)。在外部k为循环之前,将j初始化为零,这个while循环将解析所有被“|”分隔的令牌,除了最后一个。因此,在while循环之后,我们使用std来提取最后一个子字符串::::npos表示我们希望从oldDelimiter中提取所有字符,直到字符串结束为止。注意,变量newLine、num、variable和jTracker都不需要。

In fact, we can combine the two while loops to get:

事实上,我们可以把两者结合起来得到:

std::string line;  // don't need parsingArray any more
int j = 0;  // initialize j before looping over file
while (std::getline(inFile, line, '\n')) {
    int oldDelimiter = 0, newDelimiter = 0;
    while ((newDelimiter = line.find("|", oldDelimiter)) != std::string::npos) {
        parsingArray2[j] = line.substr(oldDelimiter, ((newDelimiter)-oldDelimiter)); //the pipe delimited strings are isolated in input2[]
        oldDelimiter = newDelimiter + 1; //oldDelimiter is set to the next pipe delimiter.
        ++j; // increment j
    }
    // get the last token and increment j
    parsingArray2[j] = line.substr(oldDelimiter, std::string::npos); //the pipe delimited strings are isolated in input2[]
    ++j;
    // increment count
    ++count;
}

which eliminates the need for the outer k for loop. Note also that the array parsingArray is no longer needed as there is no longer a need to store intermediate results accumulated from one loop to be iterated over and used in a subsequent loop.

这就消除了外层k循环的需要。还要注意,数组parsingArray不再需要,因为不再需要存储从一个循环中累积的中间结果,并在随后的循环中循环使用。

Additional notes to consider:

额外的考虑:

  1. Use std::vector instead of fixed size arrays for std::string and InventoryItem.
  2. 使用std::向量代替std的固定大小数组::string和InventoryItem。
  3. Declare variables "locally" for reasons discussed in this link.
  4. 在此链接中声明变量“本地”。
  5. In the subsequent for loop that sets the items, there is an assumption that the file contains exactly four tokens for each line (and that the tokens are exactly the item number (integer number), description (character string), cost (real number), and unit (integer number) in that order). You should carefully consider what will happen if the file does not satisfy this requirement (i.e., input data error), and how your program should handle all error cases. Maybe the code within that loop can be incorporated within the nested while loops so that errors can be detected and properly handled as the file is being parsed?
  6. 在随后的for循环中设置项目,假设文件中包含了每一行的四个标记(而令牌恰好是该顺序的项目编号(整数)、描述(字符串)、成本(实数)和单位(整数))。您应该仔细考虑如果文件不满足此要求会发生什么(即:,输入数据错误),以及程序应该如何处理所有的错误。也许该循环中的代码可以包含在嵌套的while循环中,以便在解析文件时能够检测和正确处理错误。

#1


0  

There are two issues with your code involving the use of for loops when it is better to use while. The first issue involves the block of code:

您的代码中有两个问题涉及到在使用时使用for循环。第一个问题涉及到代码块:

for (int i = 0; inFile; i++) {
    getline(inFile, parsingArray[i], '\n');
    count++;//count will be needed for counting iterations of for loop for InventoryItem object data field completion
}

Here, count is incremented even after we have reached the end of the file. As a result, count will be one more than the number of lines in the file. We can use a while loop instead:

在这里,即使我们已经到达文件的末尾,计数仍然是递增的。因此,count将比文件中的行数多一个。我们可以用while循环来代替:

while (getline(inFile, parsingArray[count], '\n')) 
  ++count;

Here, getline will set the end-of-file flag for the inFile ifstream when the last line is read so that the while loop exits. With count initialized to zero before this while loop, the resulting count will correctly reflect the number of lines in the file.

在这里,getline将在最后一行读取时为inFile ifstream设置文件结束标志,以便while循环退出。在此while循环之前,将count初始化为零,结果计数将正确地反映文件中的行数。

The second issue involves the block of code:

第二个问题涉及代码块:

for (int j = jTracker; num < variable; j++) {//jTracker continues to grow through multiple outer "k" loops.
    newDelimiter = parsingArray[k].find("|", oldDelimiter);      //newDelimiter becomes the further pipe delimiter in the line.
    parsingArray2[j] = parsingArray[k].substr(oldDelimiter, ((newDelimiter)-oldDelimiter));//the pipe delimited strings are isolated in input2[]
    oldDelimiter = newDelimiter + 1;//oldDelimiter is set to the next pipe delimiter.


    variable = parsingArray[k].length();
    //The following alters variables as needed for the next loop
    num = newDelimiter;
    jTracker = (j + 1);
    newLine = j;
}

As pointed out by others, num and variable are both set to zero before this for loop so that the condition num < variable is never met. Therefore, the code within the for loop is never executed. Again, a while loop here will do:

正如其他人指出的那样,num和变量在循环之前都被设置为0,这样就不会满足条件num <变量。因此,for循环中的代码永远不会被执行。再一次,这里的while循环将会:< p>

while ((newDelimiter = parsingArray[k].find("|", oldDelimiter)) != std::string::npos) {
    parsingArray2[j] = parsingArray[k].substr(oldDelimiter, ((newDelimiter)-oldDelimiter)); //the pipe delimited strings are isolated in input2[]
    oldDelimiter = newDelimiter + 1; //oldDelimiter is set to the next pipe delimiter.
    ++j; // increment j
}
// get the last token and increment j
parsingArray2[j] = parsingArray[k].substr(oldDelimiter, std::string::npos); //the pipe delimited strings are isolated in input2[]
++j;

Here, find will return std::string::npos if there are no more delimiters (i.e., "|") to find. With j initialized to zero before the outer k for loop, this while loop will parse all tokens delimited by "|" except for the last one. Therefore, after the while loop, we extract the last substring using std::string::npos to denote that we want all characters from oldDelimiter until the end of the string. Note that the variables newLine, num, variable, and jTracker are all not needed.

这里,find将返回std::字符串::npos,如果没有更多的分隔符(也就是。“|”)。在外部k为循环之前,将j初始化为零,这个while循环将解析所有被“|”分隔的令牌,除了最后一个。因此,在while循环之后,我们使用std来提取最后一个子字符串::::npos表示我们希望从oldDelimiter中提取所有字符,直到字符串结束为止。注意,变量newLine、num、variable和jTracker都不需要。

In fact, we can combine the two while loops to get:

事实上,我们可以把两者结合起来得到:

std::string line;  // don't need parsingArray any more
int j = 0;  // initialize j before looping over file
while (std::getline(inFile, line, '\n')) {
    int oldDelimiter = 0, newDelimiter = 0;
    while ((newDelimiter = line.find("|", oldDelimiter)) != std::string::npos) {
        parsingArray2[j] = line.substr(oldDelimiter, ((newDelimiter)-oldDelimiter)); //the pipe delimited strings are isolated in input2[]
        oldDelimiter = newDelimiter + 1; //oldDelimiter is set to the next pipe delimiter.
        ++j; // increment j
    }
    // get the last token and increment j
    parsingArray2[j] = line.substr(oldDelimiter, std::string::npos); //the pipe delimited strings are isolated in input2[]
    ++j;
    // increment count
    ++count;
}

which eliminates the need for the outer k for loop. Note also that the array parsingArray is no longer needed as there is no longer a need to store intermediate results accumulated from one loop to be iterated over and used in a subsequent loop.

这就消除了外层k循环的需要。还要注意,数组parsingArray不再需要,因为不再需要存储从一个循环中累积的中间结果,并在随后的循环中循环使用。

Additional notes to consider:

额外的考虑:

  1. Use std::vector instead of fixed size arrays for std::string and InventoryItem.
  2. 使用std::向量代替std的固定大小数组::string和InventoryItem。
  3. Declare variables "locally" for reasons discussed in this link.
  4. 在此链接中声明变量“本地”。
  5. In the subsequent for loop that sets the items, there is an assumption that the file contains exactly four tokens for each line (and that the tokens are exactly the item number (integer number), description (character string), cost (real number), and unit (integer number) in that order). You should carefully consider what will happen if the file does not satisfy this requirement (i.e., input data error), and how your program should handle all error cases. Maybe the code within that loop can be incorporated within the nested while loops so that errors can be detected and properly handled as the file is being parsed?
  6. 在随后的for循环中设置项目,假设文件中包含了每一行的四个标记(而令牌恰好是该顺序的项目编号(整数)、描述(字符串)、成本(实数)和单位(整数))。您应该仔细考虑如果文件不满足此要求会发生什么(即:,输入数据错误),以及程序应该如何处理所有的错误。也许该循环中的代码可以包含在嵌套的while循环中,以便在解析文件时能够检测和正确处理错误。