1

I have a file that I am reading data from, the data is in the format [function] [number1] [number2] where [number2] is optional!
Eg.

+ 88 19  
- 29 28 
! 4
+ 2 2

Output from above:

107
1

My code works just fine for when the line is in the format [function] [number1] [number2] but my code fails when [number2] does not exist in a line.

My code so far:

Libraries I am using:
iostream
fstream
cstdlib
string
...

while (infile >> function >> number1>> number2)
{
    switch (function)
    {
    case '+':

        addition(number1, number2);
        break;

    case '-':

        subtraction(number1, number2);
        break;

    case '!':

        factorial(number1);
        break;

...

How can I read [number1] only and skip back to [function] on the next read IF [number2] does not exist.

Any help is appreciated,
Thanks!

Hamza
  • 13
  • 3

3 Answers3

0

You should read from file line by line.

Then, you should parse each line by ' '. You can use a boolean variable and make it true when you reach the second space. If you reach at the end of string and the boolean is still false, then you didn't have any number 2.

Carl
  • 2,057
  • 1
  • 15
  • 20
Arian B
  • 79
  • 1
  • 9
0

This would be one way that accommodates your approach, but makes less assumptions about input. Keep in mind that this code is rather specific to your chosen format and trusts 100% that the file you're reading from is correct. As people have mentioned in comments, reading the line and parsing it would be more reliable, and probably what you should consider for future endeavours. This does however follow your current approach cloesly, with a few modifications.

const bool isUnary(char function)
{
    if (function == '!') return true;

    // Add further unary functions here as if/switch

    return false
}

int main()
{
    // Only read function here
    while (infile >> function)
    {
        // Prepare your numbers
        int number1{}, number2{};

        // If the function is Unary (IE: Takes one parameter)
        if (isUnary(function))
        {
            infile >> number1; // Read the one number
        }

        // Otherwise read both numbers
        else
        {
            infile >> number1;
            infile >> number2;
        }

        // Then switch on function as you otherwise would
        switch (function)
        {
        case '+':
            addition(number1, number2);
            break;
        case '-':
            subtraction(number1, number2);
            break;
        case '!':
            factorial(number1);
            break;
        }
    }

    return 0;
}
Carl
  • 2,057
  • 1
  • 15
  • 20
  • What if "infile >> number1" fails? What if someone makes a letter instead of a number? What if more tokens are on one line then was specified? All parsing code should always check the fail bit of streams. You mentioned this code makes the assumption that the file is fine, but I feel like it is important to really shove the "Check the Failbit" mantra down the throats of new people. – Christopher Pisz Mar 20 '18 at 21:13
0

You can use some tricks; You have at least at the beginning of each line an arithmetic operator character eg( "+ - *") And at least one argument follows it. So you can use a variable of type character to get the operator and after its read inside the loop you read the remaining whole line then we use the API strtok passing to it space (' ').

Inside the loop after reading the operator and the line we switch according to the operator we call strtok to parse the line and atoito convert to integer the results.

Here is a simple program I elaborated for you which I think it works fine:

#include <cstring>
#include <string>
#include <iostream>
#include <fstream>
//using namespace std;

// some forward declarations
int Add(int, int = 0); // as long as you said the second parameter is optional
int Sub(int, int = 0);
int Mult(int, int = 0);
int Div(int, int = 0);
int Fact(int);



int main(){

    std::ifstream in("data.txt");
    std::string sLine;
    char op;
    int param1, param2;

    while(in >> op){    // getting the first character from the file which is considered to be the operator
        std::getline(in, sLine); // after reading the operator above we read the remaining whole line containing 1 or 2 integer values.

        switch(op){
            case '+':{
                // some parsing and converting here
                char* token = strtok((char*)&sLine[0], " ");
                while(token){
                    param1 = atoi(token);
                    token = strtok(NULL, " ");
                    param2 = atoi(token);
                    token = strtok(NULL, " ");
                    // calling relevant functions and printing
                    std::cout << param1 << " " << op << " " 
                        << param2 << " = " << 
                        Add(param1, param2) << std::endl;

                }
            }
            break;
            case '-':{
                char* token = strtok((char*)&sLine[0], " ");
                while(token){
                    param1 = atoi(token);
                    token = strtok(NULL, " ");
                    param2 = atoi(token);
                    token = strtok(NULL, " ");
                    std::cout << param1 << " " << op << " " 
                        << param2 << " = " << 
                        Sub(param1, param2) << std::endl;
                }

            }
            break;
            case '*':{
                char* token = strtok((char*)&sLine[0], " ");
                while(token){
                    param1 = atoi(token);
                    token = strtok(NULL, " ");
                    param2 = atoi(token);
                    token = strtok(NULL, " ");
                    std::cout << param1 << " " << op << " " 
                        << param2 << " = " << 
                        Mult(param1, param2) << std::endl;
                } 
            }
            break;
            case '/':{
                char* token = strtok((char*)&sLine[0], " ");
                while(token){
                    param1 = atoi(token);
                    token = strtok(NULL, " ");
                    param2 = atoi(token);
                    token = strtok(NULL, " ");
                    std::cout << param1 << " " << op << " " 
                        << param2 << " = " << 
                        Div(param1, param2) << std::endl;
                }

            }
            break;
            case '!':{
                char* token = strtok((char*)&sLine[0], " ");
                while(token){
                    param1 = atoi(token);
                    token = strtok(NULL, " ");
                    std::cout << param1 << op << " = " << 
                        Fact(param1) << std::endl;
                }                
            }
            break;
        }

    }

    in.close(); // graceful close

    std::cout << std::endl;
    std::cin.get();
    return 0;
}

int Add (int a, int b) { return a + b;}
int Sub (int a, int b) { return a - b;}
int Mult(int a, int b) { return a * b;}
int Div (int a, int b) { return a / b;}
int Fact(int a) { 

    int tmp(a - 1);
    while( tmp)
        a *= tmp--;

    return a;
}

The file data.txt content:

+ 88 19  
- 29 28 
! 4
+ 2 2

The output:

88 + 19 = 107
29 - 28 = 1
4! = 24
2 + 2 = 4
Raindrop7
  • 3,889
  • 3
  • 16
  • 27