简体   繁体   English

C ++ fstream,从文本读取数据并执行数学运算?

[英]C++ fstream, reading data from text and preforming math operations?

I am at my wits end here. 我的智慧到此为止。 I am writing a program in C++ that will read a text file that contains the following as a brief example: 我正在用C ++写一个程序,它将读取一个文本文件,其中包含以下内容作为简要示例:

+ 23 34
- 9 8
+ 100 1
* 8 7
^ 2 5
/ 45 8

The reader will store the first operands in a char type and based on the char it retrieves, a function will be called to preform the operation on the two numbers, here's a sample functions that will do this. 读取器将第一个操作数存储为char类型,并根据检索到的char调用一个函数以对这两个数字进行运算,下面是一个示例函数。

void doDivision(ifstream &inFile) {
    char ch;
    int num1, num2;

    inFile >> ch >> num1 >> num2;
    cout << "Division     " << num1 << "    " << num2 << "    " << "Quotient " << "    " << num1/num2 << " Remain " << num1%num2  << endl; 
}

One thing is I am not sure why the argument is &inFile this function prototype is not made by me, but it is from a book maybe this is why I cannot I get it to work. 一件事是我不确定为什么参数是&inFile这个函数原型不是我制作的,但这是从书中得到的,也许这就是为什么我不能使它起作用。

Here is my main function: 这是我的主要功能:

int main()
{

ifstream inFile;
char ch;
int num1, num2;

inFile.open("math.txt");
if (inFile.fail())
{
cout << ch;
      cout << "The math.txt input file failed to open";
        return -1;
}


 while(inFile)
{
    switch (ch) {

    case '+':
        doAddition(inFile);
        break;
    case '-':
        doSubtraction(inFile);
        break;
    case '*':
        doMultiplication(inFile);
        cout << "debug " << ch;
        break;
    case '/':
        doDivision(inFile);
        break;
    case '!':
        doFactorial(inFile);
        break;
    default:
        cout << "Invalid Operation" << endl;

    }

    inFile >> ch;
}

inFile.close();
return 0;
}

All of this together produces the following unintended result 所有这些共同产生以下意外结果

Invalid Operation 
Addition 3 34 sum 37 (wrong data in text file is 23 and 34)
subtraction 0 8 difference 8 (data in textfile is 9 and 8 respectively)

How would I implement this, I am overwhelmed since I have never worked with files before. 我将不知道如何处理这个问题,因为我以前从未使用过文件。

One simple error is that inside of your while() loop, you don't call inFile >> ch until after the first time through the loop. 一个简单的错误是,在while()循环内部,直到第一次通过循环后才调用inFile >> ch Try fixing that and see if it helps. 尝试修复该问题,看看是否有帮助。

Also, what Aniket said in their answer is another problem you need to look out for. 另外, 阿尼凯特(Aniket)在回答中所说的是您需要注意的另一个问题。

So in short, your loop should look roughly like this: 简而言之,您的循环应大致如下所示:

inFile >> ch;
while(inFile) {
    switch(ch) {
    case '+':
        ...
    }
    inFile >> ch;
}

And your functions should be similar to this: 并且您的功能应与此类似:

void doDivision(ifstream &inFile) {
    int num1, num2;

    inFile >> num1 >> num2;

    ...
}

Since you are already doing inFile >> ch in main() it will be wrong(logically) to read it again in doAddition() and other methods. 由于您已经在main()执行inFile >> ch ,因此从逻辑上在doAddition()和其他方法中再次读取它是错误的。

since you've posted doDivision() method where you read in the ch character, I am assuming you're doing the same in doAddition() as well. 由于您已经发布了doDivision()方法并在其中读取了ch字符,因此我假设您在doAddition()中也是如此。

Also your output: 还有你的输出:

Addition 3 34 sum 37 (wrong data in text file is 23 and 34) 加法3 34的总和37(文本文件中的错误数据是23和34)

Tells us all - you've read 1 character(found + ) then read another character in doAddition() method, - which read 2 into ch of doAddition() then read 3 and 34 .. 告诉我们所有内容-您已读取1个字符(找到+ ),然后在doAddition()方法中读取了另一个字符,-将2读入了doAddition() ch ,然后读取了334 .。

This is where the error actually is. 这实际上是错误所在。

Solution: change your doAddition() and all other functions to something like below. 解决方案:将doAddition()和所有其他函数更改为如下所示。

void doAddition(ifstream &inFile) {
    char ch;
    int num1, num2;

    inFile >> num1 >> num2;
    cout << "Addition of " << num1 << " and " << num2 << " = "<< (num1+num2) << '\n';
}

Also, in the main() function: 另外,在main()函数中:

the while loop should look like this: while循环应如下所示:

while(inFile)
{
    inFile >> ch;
    switch (ch) {

    case '+':
        doAddition(inFile);
        break;
    case '-':
        doSubtraction(inFile);
        break;
    case '*':
        doMultiplication(inFile);
        cout << "debug " << ch;
        break;
    case '/':
        doDivision(inFile);
        break;
    case '!':
        doFactorial(inFile);
        break;
    default:
        cout << "Invalid Operation" << endl;

    }
}

You do not read into ch for the first iteration. 您不会在第一次迭代中读入ch In fact, when you check that your file opened with no problem, you do cout << ch; 实际上,当您检查文件打开没有问题时,可以执行cout << ch; despite the fact that ch is uninitialized. 尽管ch未初始化。 You could simply move the inFile >> ch; 您可以简单地移动inFile >> ch; to the top of the while loop. while循环的顶部。

The next problem is that inside each of your doSomething functions, you are doing inFile >> ch again, which will attempt to read the operation character again. 下一个问题是,在每个doSomething函数中,您都在执行inFile >> ch ,这将尝试再次读取操作字符。 Your doSomething functions don't need to know ch though, since the function itself was chosen based on the value of ch . 但是,您的doSomething函数不需要知道ch ,因为该函数本身是根据ch的值选择的。

Here is how I would write this: 这是我的写法:

ifstream inFile("math.txt"); // You can specify the file name here
char op;
int left_operand, right_operand;

// Use extraction has while condition
while (inFile >> op >> left_operand >> right_operand) {
  switch (op) {
    // Pass operands to the relevant function
    case '+': doAddition(left_operand, right_operand); break;
    // ...
  }
}

// You do not need to close inFile, it will be closed when it goes out of scope
return 0;

Ideally, there are better ways of doing what you suggest, but if you have to make your code look and perform like this, then the appropriate solution should be something of this sort: 理想情况下,有更好的方法可以执行建议的操作,但是如果您必须使代码看起来像这样并执行,那么适当的解决方案应该是这样的:

#include <vector>
#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib>

using namespace std;

void doAddition(ifstream &inFile) {
    int num1, num2;

    inFile >> num1 >> num2;
    cout << "Addition of " << num1 << " and " << num2 << " = "<< (num1+num2) << '\n';   
}

void doSubtraction(ifstream &inFile) {
    int num1, num2;

    inFile >> num1 >> num2;
    cout << "Subtraction of " << num1 << " and " << num2 << " = "<< (num1-num2) << '\n';
}

void doMultiplication(ifstream &inFile) {
    int num1, num2;

    inFile >> num1 >> num2;
    cout << "Multiplication of " << num1 << " and " << num2 << " = "<< (num1*num2) << '\n';
}

void doDivision(ifstream &inFile) {
    float num1, num2;

    inFile >> num1 >> num2;
    cout << "Division of " << num1 << " and " << num2 << " = "<< (num1/num2) << '\n';
}

void doFactorial(ifstream &inFile) {
    int t1, t2;

    inFile >> t1 >> t2;

    //perform factorial here
}

void readToNextLine(ifstream& inFile) {
    string t1, t2;

    inFile >> t1 >> t2;
}

int main()
{
    ifstream inFile;
    char ch;
    int num1, num2;

    inFile.open("math.txt");

    if (inFile.is_open()){

        inFile >> ch;
        while (!inFile.eof())
        {
            switch (ch) 
            {

                case '+':
                    doAddition(inFile);
                    break;
                case '-':
                    doSubtraction(inFile);
                    break;
                case '*':
                    doMultiplication(inFile);
                    break;
                case '/':
                    doDivision(inFile);
                    break;
                case '!':
                    doFactorial(inFile);
                    break;
                default:
                    readToNextLine(inFile);
                    cout << "Invalid Operation" << endl;
            }
            inFile >> ch;
        }
            inFile.close();
    }
    else
    {
        cout << "The math.txt input file failed to open";
        return -1;
    }

    inFile.close();
    return 0;
}

A couple things to note here: 这里需要注意几件事:

Some of the solutions that the others suggested, do not consider the default case - which simply forgoes reading the rest of the line, resulting in logic errors - which no one wants. 其他人建议的某些解决方案则不考虑默认情况 ,因为这种情况只是简单地读了其余的行, 从而导致逻辑错误 ,这是没人希望的。

Now, as for a "better", more general solution, it would be more ideal to store everything as strings first, then tokenize, and attempt to convert the appropriate token to the desired type output. 现在,对于“更好”的通用解决方案,将所有内容都首先存储为字符串,然后进行标记化,然后尝试将适当的标记转换为所需的类型输出,将是更理想的选择。

But, as I noted before, if you wish to conform to the code you had previously, then this is appropriate. 但是,正如我之前指出的,如果您希望遵循以前的代码,那么这是合适的。

Unless you're feeling masochistic, it's almost certainly easiest to read the operator and two operands all at once, then carry out the operation: 除非您感到受虐狂,否则几乎可以肯定,一次读取所有运算符和两个操作数,然后执行该操作最简单:

char operation;
int operand1, operand2;

while (infile >> op >> operand1 >> operand2) 
   switch(operation) {
       case '+': add(operand1, operand2); break;
       case '-': sub(operand1, operand2); break;
       case '*': mul(operand1, operand2); break;
       case '/': div(operand1, operand2); break;
   }

For only four operators, this works well enough as-is. 仅对于四个操作员,它可以按原样运行。 If you're going to have many more, you'd probably be better off using a table of pointers to functions instead: 如果您将拥有更多功能,最好使用指向函数的指针表:

typedef int (*op)(int, int);

op operators[UCHAR_MAX];

for (int i=0; i<UCHAR_MAX; i++)
    operators[i] = report_bad_operator;

operators['+'] = add;
operators['-'] = sub;
operators['/'] = div;
operators['*'] = mul;
// more operators here

while (infile >> operation >> operand1 >> operand2)
    operators[operation](operand1, operand2);

The obvious reason/time to do otherwise would be to deal with non-binary operators (ie, ones that don't necessarily take exactly two operands). 否则的明显原因/时间将是处理非二进制运算符(即,不一定要使用两个操作数的运算符)。

First of all, you are reading chr, before assigning a value to it. 首先,您正在阅读chr,然后为其分配值。

Change your while loop like this: 像这样更改while循环:

while(inFile)
{
    inFile >> ch; // assign before reading
    switch (ch) {

    case '+':
        doAddition(inFile);
        break;
    case '-':
        doSubtraction(inFile);
        break;
    case '*':
        doMultiplication(inFile);
        cout << "debug " << ch;
        break;
    case '/':
        doDivision(inFile);
        break;
    case '!':
        doFactorial(inFile);
        break;
    default:
        cout << "Invalid Operation" << endl;
    }
}

And change your doDivision function like this: 并按以下方式更改doDivision函数:

void doDivision(ifstream &inFile)
{ 
    int num1, num2;

    inFile >> num1 >> num2; // your already read the arithmetic operator
    cout << "Division     " << num1 << "    " << num2 << "    " << "Quotient " << " 
}

First, initial pass, your ch variable is not initialized. 首先,初始阶段,您的ch变量未初始化。 It is initialized at the bottom of the loop. 它在循环的底部初始化。

Try adding: 尝试添加:

 inFile >> ch;

before the while loop. 在while循环之前。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM