0

私はここで頭がいっぱいです。簡単な例として、次の内容を含むテキスト ファイルを読み取るプログラムを C++ で作成しています。

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

リーダーは最初のオペランドを char 型に格納し、取得した char に基づいて、関数を呼び出して 2 つの数値の操作を実行します。これを行うサンプル関数を次に示します。

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

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

引数が &inFile である理由がわかりませんが、この関数プロトタイプは私が作成したものではありませんが、本からのものである可能性があります。

これが私の主な機能です:

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

これらすべてが合わさって、次の意図しない結果が生じます

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)

これをどのように実装すればよいでしょうか。これまでファイルを操作したことがないので圧倒されます。

4

7 に答える 7

4

inFile >> ch単純なエラーの 1 つは、while() ループ内で、最初にループを通過するまで呼び出さないことです。それを修正してみて、それが役立つかどうかを確認してください。

また、Aniket が回答で述べたことは、注意が必要なもう 1 つの問題です。

つまり、ループは大まかに次のようになります。

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

関数は次のようになります。

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

    inFile >> num1 >> num2;

    ...
}
于 2013-03-08T22:57:07.440 に答える
2

あなたはすでにやっているのでinFile >> ch、他の方法でもうmain()一度読むのは(論理的に)間違っていdoAddition()ます。

doDivision()キャラクターを読む方法を投稿したのでch、同じことをしていると思いますdoAddition()

また、あなたの出力:

加算 3 34 合計 37 (テキスト ファイルの間違ったデータは 23 と 34)

私たちにすべてを教えてください-あなたは1文字を読んだ(見つかった+)次にdoAddition()メソッドで別の文字を読み2ました-それはchofdoAddition()を読み込ん3でから読み34ました..

これが実際のエラーの場所です。

解決策:あなたdoAddition()と他のすべての機能を以下のようなものに変更してください。

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

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

また、main()関数で:

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;

    }
}
于 2013-03-08T22:57:23.337 に答える
2

ch最初の反復では読み取りません。実際、ファイルが問題なく開かれたことを確認すると、初期化されていないcout << ch;にもかかわらず、問題なく開いてchいます。をループinFile >> ch;の先頭に移動するだけです。while

次の問題は、各doSomething関数内inFile >> chで操作文字を再度読み取ろうとすることです。ただし、関数自体は の値に基づいて選択されているため、関数がdoSomething知る必要はありません。chch

これが私がこれを書く方法です:

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;
于 2013-03-08T22:57:46.893 に答える
1

理想的には、あなたが提案したことを行うためのより良い方法がありますが、コードをこのように見せて実行する必要がある場合、適切な解決策は次のようなものでなければなりません:

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

ここで注意すべき点がいくつかあります。

他の人が提案した解決策の中には、デフォルトのケースを考慮していないものがあります。これは、行の残りの部分を読むことを単に忘れ、論理エラーを引き起こします。これは誰も望んでいません。

さて、「より良い」より一般的な解決策として、最初にすべてを文字列として保存し、次にトークン化し、適切なトークンを目的の型出力に変換しようとするのがより理想的です。

しかし、前に述べたように、以前のコードに準拠したい場合は、これが適切です。

于 2013-03-08T23:34:26.460 に答える
0

まず、初期パスですch。変数は初期化されていません。ループの最下部で初期化され ます

追加してみてください:

 inFile >> ch;

whileループの前。

于 2013-03-09T01:09:01.477 に答える
0

マゾヒスティックな気分でない限り、演算子と 2 つのオペランドを一度に読み取ってから操作を実行するのがほぼ確実に最も簡単です。

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

オペレーターが 4 人だけの場合、これはそのままで十分に機能します。さらに多くの関数を使用する場合は、代わりに関数へのポインターのテーブルを使用することをお勧めします。

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

それ以外の場合の明白な理由/時間は、非二項演算子 (つまり、必ずしも正確に 2 つのオペランドを取るとは限らない演算子) を処理することです。

于 2013-03-08T23:03:18.427 に答える
0

まず第一に、値を割り当てる前に chr を読んでいます。

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

doDivision 関数を次のように変更します。

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

    inFile >> num1 >> num2; // your already read the arithmetic operator
    cout << "Division     " << num1 << "    " << num2 << "    " << "Quotient " << " 
}
于 2013-03-08T23:06:44.443 に答える