1

TEXT FILE IM READING

1 1 1
1.2 -2.3 0.4
-2 -3 -4
+0 -2 8.85
2.345

My code:

#include <iostream>
#include <fstream>

using namespace std;

double readFile(ifstream &myfile, double &a, double &b, double &c);
int main()
{
    int counter = 0;
    double a, b, c;
    string line, inputFile, outputFile;

    cout << "Enter the name of your input file: ";
    cin >> inputFile;

    cout << "Enter the name of your output file: ";
    cin >> outputFile;

    ifstream myfile(inputFile);
    if(myfile.is_open())
    {
        while(!myfile.eof())
        {
            readFile(myfile, a, b, c, counter);
            calculations(a, b, c);
        }


    }
    else cout << "unable to open file";
    return 0;
}

double readFile(ifstream &myfile, double &a, double &b, double &c)
{
    //Reads one line of the file
    myfile >> a >> b >> c;
    cout << a << " " << b << " " << c << endl;

}

What i want to do is that if the last line does not have 3 values i want to have some sort of stop code where it stops the processing if it has less than 3 values and the leftovers values from the previous line wont be assigned

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85

3 Answers3

1

std::istream sets failbit when operator>> failed to extract value from stream. In your code, failbit will be set if it fails to parse 3 values that can be parsed into double, and you can query if failbit is set by std::failbit().

double readFile(ifstream &myfile, double &a, double &b, double &c)
{
    myfile >> a >> b >> c;

    if(myfile.fail())
    {
        // failbit is set if one of a, b or c is not parsed successfully.
        // do some stop code here.
    }

    cout << a << " " << b << " " << c << endl;

}

Remember, std::istream does nothing for further operation if failbit is set. If you're needed to continue reading from the stream, you should clear failbit by calling std::clear().

John Park
  • 1,644
  • 1
  • 12
  • 17
1

Your biggest issue is that >> skips leading whitespace, so it doesn't differentiate between a ' ' (space) or '\n' -- it's just whitespace. To handle it correctly, you need to read each line into a std::string and then create a std::stringstream from the line.

Then read your three double values from the std::stringstream with >>. That way you can read no more double values than are present in the line. Otherwise if you just try and use >>, you will happily read 2 double values from one line and the third from the next without any indication of that happening.

You next need your function to indicate success/failure of reading the three double values from the line. A return type of bool is all you need. If you read three valid double values, return true and do your calculations() otherwise, if you return false, stop trying to read from the file.

A short example would be:

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

bool read3doubles (std::ifstream& f, double& a, double& b, double& c)
{
    std::string line {};                /* std::string to hold line */
    
    if (getline (f, line)) {            /* if line read from file */
        std::stringstream ss(line);     /* create stringstream from line */
        if (ss >> a >> b >> c)          /* if 3 doubles read from line */
            return true;                /* return true */
    }
    
    return false;   /* otherwise, return false */
}

void calculations (double& a, double& b, double& c)
{
    std::cout << a << "  " << b << "  " << c << '\n';
}

int main (int argc, char **argv) {

    if (argc < 2) { /* validate at least 1 argument given */
        std::cerr << "error: insufficient number of arguments.\n"
                    "usage: " << argv[0] << " <filename>\n";
        return 1;
    }

    std::ifstream f (argv[1]);          /* open file-stream with 1st argument */
    double a, b, c;
    
    if (!f.good()) {    /* validate file open for reading */
        std::cerr << "errro: file open failed '" << argv[1] << "'.\n";
        return 1;
    }

    while (read3doubles(f, a, b, c))    /* while 3 doubles read from file */
        calculations (a, b, c);         /* do your calculation */
    
}

(note: the calculations() function just outputs the three doubles when successfully read)

Example Use/Output

Using your input in the file dat/3doubles.txt, you would have:

$ ./bin/read3doubles dat/3doubles.txt
1  1  1
1.2  -2.3  0.4
-2  -3  -4
0  -2  8.85

Let me know if you have further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
0

I added a different function that chops a line by space and converts them to numbers. Your main function remains largely unaffected. Though I made some changed like adding a std::vector, early return to remove some nesting.

Also, I changed the main while condition from eof to std::getline.

  • Operations on std::string_view are very cheap.

  • This way you can check on every line that the number of values read is always what you need.

  • For bad input, you can easily debug if a line/ word is not number by printing it in the exception catcher.

#include <iostream>
#include <fstream>
#include <vector>
using namespace std;

void read_values(std::string_view line, std::vector<double> &values);
void calculations(int, int, int);
int main()
{
  string inputFile, outputFile;

  cout << "Enter the name of your input file: ";
  cin >> inputFile;

  cout << "Enter the name of your output file: ";
  cin >> outputFile;

  ifstream myfile(inputFile);
  if (!myfile.is_open()) {
    cout << "unable to open file";
    return -1;
  }

  std::string line;
  std::vector<double> values;
  while (std::getline(myfile, line, '\n')) {
    read_values(line, values);
    std::cout << values.size();
  }
  return 0;
}

void read_values(std::string_view line, std::vector<double> &values)
{
  while (!line.empty()) {
    const std::string_view::size_type pos_space{line.find(' ')};
    try {
      values.push_back(std::stod(std::string(line.substr(0, pos_space))));
    }
    catch (const std::invalid_argument &ex) {
      std::cout << ex.what() << std::endl;
      return;
    }
    line.remove_prefix(pos_space + 1);
  }
}

puio
  • 1,208
  • 6
  • 19