为什么我的错误会破坏我的程序? C ++

时间:2016-08-20 04:28:03

标签: c++ arrays object invalid-argument

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

这是我的

的头文件
// 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

这是我的主要包含的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";
        }

    }
}

分配是创建一个程序,执行帮助菜单中描述的所有操作。我开始用&#34;我&#34;这是输入文本文件&#39;信息到InventoryItem项目数组中,包含项目描述,项目成本和项目单元总数。此外,应包括inventoryitem#,但该对象持有的阵列点与项目编号相同,因此不需要变量。

我尝试运行该程序,它运行。我输入&#34; i&#34;作为我的命令。它要求输入文件,我使用文件&#34; plumbing.txt&#34;。 Plumbing.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

输入&#34; plumbing.txt&#34;后,我点击输入,程序程序。

看起来像这样:

&#34;命令:

输入输入的文件名: plumbing.txt &#34; 程序中断了。

我将代码的一部分缩小到实际导致程序破坏的部分以及代码的这一部分:

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);
            }

请帮我弄清楚为什么我的程序会破坏。我想不明白。我试图将输入作为文件中的字符串读取,将字符串解析为单独的数据片段。使用stoi或stof从字符串转换为整数或双精度,并将信息输入到对象数组中。感谢您阅读并提供任何帮助。

1 个答案:

答案 0 :(得分:0)

如果最好使用for,您的代码有两个问题涉及使用while循环。第一个问题涉及代码块:

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
}

这里,即使我们到达文件末尾,count也会递增。因此,count将比文件中的行数多一个。我们可以使用while循环:

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

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

第二个问题涉及代码块:

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;
}

正如其他人所指出的,numvariable在此for循环之前都设置为零,因此永远不会满足条件num < variable。因此,for循环中的代码永远不会执行。同样,这里有一个while循环:

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;

如果找不到更多分隔符(即find),std::string::npos将返回"|"。在外部 j k循环之前将for初始化为零,此while循环将解析由"|"分隔的所有令牌,但为了最后一个。因此,在while循环之后,我们使用std::string::npos提取最后一个子字符串,表示我们希望所有字符都从oldDelimiter到字符串结尾。请注意,变量newLinenumvariablejTracker都不是必需的。

实际上,我们可以将两个while循环组合起来得到:

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;
}

,无需外部k for循环。另请注意,不再需要数组parsingArray,因为不再需要存储从一个循环累积的中间结果,以便迭代并在后续循环中使用。

需要考虑的其他注意事项:

  1. 使用std::vector代替std::stringInventoryItem的固定大小数组。
  2. 声明变量&#34;本地&#34; for reasons discussed in this link
  3. 在设置for的后续item循环中,假设文件中每行只包含四个标记(并且标记正是项目编号(整数) ,描述(字符串),成本(实数)和单位(整数)的顺序)。如果文件不满足此要求(即输入数据错误),以及程序应如何处理所有错误情况,您应该仔细考虑会发生什么。也许该循环中的代码可以合并到嵌套的while循环中,以便在解析文件时可以检测到并正确处理错误?