【问题标题】:Why am I getting this error breaking my program? C++为什么我在破坏我的程序时收到此错误? C++
【发布时间】:2016-12-27 06:57:31
【问题描述】:

我有一个用于我的 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";
        }

    }
}

任务是创建一个程序来执行帮助菜单中描述的所有操作。我从“i”开始,它将文本文件的信息输入到 InventoryItem 项目数组中,其中包含项目描述、项目成本和项目单元总数。另外,inventoryitem#应该包含在内,但是object持有的array点与item number是一样的,所以不需要变量。

我尝试运行程序,它运行。我输入“i”作为我的命令。它要求输入一个文件,我使用文件“plumbing.txt”。 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

一旦我在输入“plumbing.txt”后按回车,程序就会启动。

看起来像这样:

"命令:i

输入文件名:plumbing.txt" 然后程序就中断了。

我将代码部分缩小到实际导致程序中断的原因以及这部分代码中的某些内容:

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 从字符串转换为整数或双精度,并将信息输入到对象数组中。感谢您的阅读以及您能提供的任何帮助。

【问题讨论】:

  • 那么,它是如何“破解”的,究竟?你得到的确切错误是什么?您是否在调试器中单步执行了代码?您期望使用的变量有什么值?你到底发现了什么?
  • for(int j = jTracker; num &lt; variable; j++) 0什么时候会小于0?

标签: c++ arrays object invalid-argument


【解决方案1】:

当使用while 更好时,涉及使用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
}

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

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

这里,getline 将在读取最后一行时为inFile ifstream 设置文件结束标志,以便退出while 循环。在while 循环之前将count 初始化为零,生成的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 &lt; 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::stringInventoryItem,使用std::vector 而不是固定大小的数组。
  2. “本地”声明变量for reasons discussed in this link
  3. 在随后设置items 的for 循环中,假设文件每行正好包含四个标记(并且标记正是项目编号(整数)、描述(字符字符串)、成本(实数)和单位(整数)。您应该仔细考虑如果文件不满足此要求(即输入数据错误)会发生什么,以及您的程序应如何处理所有错误情况。也许该循环中的代码可以合并到嵌套的while 循环中,以便在解析文件时检测并正确处理错误?

【讨论】:

    猜你喜欢
    • 2015-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-22
    • 2019-06-23
    • 2019-11-22
    • 2018-05-13
    相关资源
    最近更新 更多