0

I have a project where I have to read from a text file and encode its contents using a Book Cipher. The first step I assume would be reading from two text files and count the page/line/column numbers(page numbers are determined by the delimiter '\f' and lines are determined by '\n'). However, I do not want the user to have to rename their file to "message.txt" everytime for the file to be read. Is there anyway for a C++ program to read any text files inputed by the user?

My current test program code:

#include <iostream>     // Basic I/O
#include <string>       // string classes
#include <fstream>      // file stream classes
#include <sstream>      // string stream classes
#include <locale>       // locale class
using namespace std;



// version 0
int main() {
    while (!cin.eof()) {
        char ch;
        cin >> ch;
        cout << ch;
    }
}

It gets everything from the file and outputs it correctly, however this way I can only accept one input file. I was hoping I can do something like this:

int main( int argc, char* argv[])

so:

argv[0] = program name
argv[1] = book cipher
argv[2] = message file
argv[3] = output file (encoded message goes here)

Is there a C++ version of this? I tried ifstream read(argv[1]), which did not work as I expected and it threw an exception. I feel like char* argv[] is something that is used in C, but not C++ as C++ has a string and strings are not a char array like in C. Wondering if someone could write me a sample just to see how the syntax work for this in C++.

And what which input function can I use to count escape characters such as '\n' and '\f'? I know from Java, I could use charAt() and do it in a loop or in C, it is just a char array. Input is really confusing for me in C/C++, I will keep looking at looking at tutorials on how these different functions work. Any ideas will be appreciated.

J J
  • 53
  • 7
  • The correct solution is to use `std::ifstream`. Unfortunately, nobody can help you if the entirety of your description is that `std::ifstream` "did not work as I expected and threw an exception". As far as "any ideas" goes, what C++ book are you using to learn C++, and what don't you understand about all the examples in that book, of using `std::ifstream`? – Sam Varshavchik Mar 13 '20 at 01:20
  • c++ is backwards-compatible with c, so `char **argv` is supported (AFAK, std::string objects are not, that is part of the standard library but not the core language). Could you copy the exception into your post so that we have a better idea of what's going wrong? – Bryan Ferris Mar 13 '20 at 01:21
  • `std::ifstream` would be correct for reading the file, but it sounds to me like you can't even get to that point - you're effectively getting stuck on how to get the filename out of the C-style argv pointer. That sound correct? – Alex Mar 13 '20 at 01:23
  • @Alex that sound correct. I couldn't get the correct arguments from them. Also, I know that C++ is backwards compatible, but if my project says I hvae to make a C++ console program. I guess my question is would char* argv[] be something used in C++? or would it be string argv[] – J J Mar 13 '20 at 01:37
  • 1
    Unrelated: `while (!cin.eof())` is a bug. See [Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-i-e-while-stream-eof-cons) for details. – user4581301 Mar 13 '20 at 01:37
  • 1
    It's still `char * argv[]`. Feel free to convert it all to a `std::vector` of `std::string` if you want to, but usually there's little need. Make sure you have enough arguments with `argc` first though. The best thing for you to do is to add the code that didn't work to the question along with the command line you used to run the program. Odds are good someone can tell you what went wrong in very short order. – user4581301 Mar 13 '20 at 01:42

1 Answers1

1

Your understanding of the main parameters argc and argv is basically correct. What you will use as comand line arguments, will be the name of the files.

In order to work with them, you need to open the files with the given filenames, then you can extract data. To open an input file, you can use an std::ifstream and use its constructor, where you pass the filename along. The boolean ! operator for the std::fstream has been overwritten and will return the state (result) of the operation. Therefore you can write if (fileStream), to check, if the open operation was successfull.

For counting something, there are many possibilities. You can use standard algorithms.

Please see some example code below:

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


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

    // Check if the number of parameters are correct
    if (4 != argc) {
        // Wrong number of arguments, inform the user
        std::cerr << "\n*** Wrong comand line parameters: please call with:\n"
            << "encode cipherFileName messageFileName outputFileName\n\n";
    }
    else
    {
        // Now, try to open all files. Open cipher file and check if this worked
        if (std::ifstream cipherFileStream(argv[1]); cipherFileStream) {

            // Open message file and check, if that worked
            if (std::ifstream messageFileStream(argv[2]); messageFileStream) {

                // And Open output file and check, if that worked
                if (std::ofstream outputFileStream(argv[3]); outputFileStream) {

                    // Read the complete message file into one string
                    std::string messageData(std::istreambuf_iterator<char>(messageFileStream), {});
                    // Count some special charcters in the message file
                    size_t newLines = std::count(messageData.begin(), messageData.end(), '\n');
                    size_t formFeeds = std::count(messageData.begin(), messageData.end(), '\f');

                    // Show result to user
                    std::cout << "\nNew lines:  " << newLines << "\nForm feeds: " << formFeeds << "\n";

                }
                else {
                    std::cerr << "\n*** Error: Could not open output file\n";
                }
            }
            else {
                std::cerr << "\n*** Error: Could not open message file\n";
            }
        }
        else {
            std::cerr << "\n*** Error: Could not open book cipher file\n";
        }
    }
    return 0;
}

Armin Montigny
  • 7,879
  • 3
  • 11
  • 29
  • Thank you. I used a much simpler version of this, but it works. The same idea :) – J J Mar 14 '20 at 19:30