Home > OS >  I am getting several errors in this section of my code in which I am trying to turn the output into
I am getting several errors in this section of my code in which I am trying to turn the output into

Time:12-10

{
    const char* fname = "myfile";   //or string fname ("str.txt") in C  11
    string input;                       //our first look at the C   string object
    fstream myfile;                     //construct fstream object for file i/o
    openfile(myfile, fname, ios_base::out); //open file for output (current contents lost)
    std::transform(myfile.open(), myfile.end(), myfile.open(), ::toupper);
    while (cout << "Enter a line ('q' to quit): " && getline(cin, input))
    {
        if (input == "q")
            break;
        else                            //exit while loop
            myfile << input << endl;    //pipe string we read file add new line character
    }
    myfile.close();                     //close our file
    std::transform(myfile.open(), myfile.end(), myfile.open(), ::toupper);
    openfile(myfile, fname, ios_base::in);  //reopen it for input
    cout << "\nHere's whats in " << fname << ":\n";
    while (getline(myfile, input))      //get and print all the lines
        cout << input << endl;
    system("pause");
}
Severity    Code    Description Project File    Line    Suppression State
Error (active)  E0304   no instance of overloaded function "std::basic_fstream<_Elem, _Traits>::open [with _Elem=char, _Traits=std::char_traits<char>]" matches the argument list   fileio2 C:\Users\burnsk\source\repos\Hello\fileio2\fileio2.cpp  14  
Severity    Code    Description Project File    Line    Suppression State
Error (active)  E0109   expression preceding parentheses of apparent call must have (pointer-to-) function type fileio2 C:\Users\burnsk\source\repos\Hello\fileio2\fileio2.cpp  14  

CodePudding user response:

std::transform(myfile.open()

That's not going to work. std::transform expects an input iterator range, typically some begin/end range. std::fstream::open doesn't return an iterator.

You probably want to look at std::istream_iterator<char>.

CodePudding user response:

We'll do a quick code review of what you've posted. I've removed most of your comments, and we'll actually use that as our first critique. The comments don't help readability at all. You're just restating the line of code, which isn't a great comment. Comments that explain 'why' or fill in the information gaps that the code alone cannot explain are much better.

// Missing includes and main()
// This does not qualify as a Minimal, Reproducible Example
// Specifically, it's not reproducible, as it cannot be copy/pasted
// and ran by the people you want to get help from.
// https://stackoverflow.com/help/minimal-reproducible-example
{
    const char* fname = "myfile";   // Hard-coded file name is meh, C-string also
    string input;                   // Prefer this EVERYWHERE
    fstream myfile;                 
    openfile(myfile, fname, ios_base::out); // No explanation of this function
                                            // It's not standard, you should
                                            // have posted its code.

    // Bad syntax, as explained. Refer to the documentation
    // https://en.cppreference.com/w/cpp/algorithm/transform
    std::transform(myfile.open(), myfile.end(), myfile.open(), ::toupper);

    // Clever, but the user likely doesn't need to be prompted before
    // every line. Instead, you could have checked for the end condition.
    while (cout << "Enter a line ('q' to quit): " && getline(cin, input))
    {
        if (input == "q")
            break;                      // This is the line that exits the loop
        else                            //exit while loop
            myfile << input << endl;    // Premature write
    }
    myfile.close();

    // See above about transform syntax being bad. But why write data
    // you don't want, close the file, re-open the file, try to
    // re-write the data, and close the file again?
    std::transform(myfile.open(), myfile.end(), myfile.open(), ::toupper);
    openfile(myfile, fname, ios_base::in);  //reopen it for input
    cout << "\nHere's whats in " << fname << ":\n";
    while (getline(myfile, input))      //get and print all the lines
        cout << input << endl;
    system("pause");
}

Since you are reading the strings in, and not caring about the original contents, why not manipulate the string to look the way you want, and then write it to the file. It's a lot simpler.

My code below does that, and uses a few other tricks to avoid copy/pasta.

The biggest change is that the user is only told what to do once, and the while() loop Boolean expression grabs the line and ensures it's not the quit condition.

The string is then run through std::transform() and fully capitalized. And then it is written to the file. This writes the data we want one time, instead of writing a bunch of bad data and then doubling back and trying to fix it.

For printing the contents of the file to the screen, we create a new class that holds a string and changes how it can be read in, essentially reading an entire line at a time instead of a word. This is not necessary, but like I said, I put some stuff in to avoid a straight copy/paste/submit situation.

#include <algorithm>
#include <cctype>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>

namespace detail {
class Line {
  std::string m_line;

 public:
  friend std::istream& operator>>(std::istream& sin, Line& line) {
    std::getline(sin, line.m_line);
    return sin;
  }

  operator std::string() const { return m_line; }
};
}  // namespace detail

int main(int argc, char* argv[]) {
  if (argc != 2) return 1;

  std::ofstream fout(argv[1]);
  if (!fout) {
    std::cerr << "Error opening file for writing.\n";
    return 2;
  }

  std::cout << "Type lines. Type \"q\" on its own line to quit.\n";
  std::string line;
  while (std::getline(std::cin, line) && line != "q") {
    std::transform(line.begin(), line.end(), line.begin(),
                   [](const auto& c) { return std::toupper(c); });
    fout << line << '\n';
  }
  fout.close();

  std::ifstream fin(argv[1]);
  if (!fin) {
    std::cerr << "Error opening file for reading.\n";
    return 3;
  }

  std::copy(std::istream_iterator<detail::Line>(fin),
            std::istream_iterator<detail::Line>(),
            std::ostream_iterator<std::string>(std::cout, "\n"));
  fin.close();
}

Output:

❯ ./a.out text.txt
Type lines. Type "q" on its own line to quit.
You'll be back, time will tell
You'll remember that I served you well
Oceans rise, empires fall
We have seen each other through it all
And when push comes to shove
I will send a fully armed battalion to remind you of my love!
q
YOU'LL BE BACK, TIME WILL TELL
YOU'LL REMEMBER THAT I SERVED YOU WELL
OCEANS RISE, EMPIRES FALL
WE HAVE SEEN EACH OTHER THROUGH IT ALL
AND WHEN PUSH COMES TO SHOVE
I WILL SEND A FULLY ARMED BATTALION TO REMIND YOU OF MY LOVE!
  •  Tags:  
  • c
  • Related