1

I have an assignment that wants me to write a program that reads a text file, then outputs a modified version of that file using a version of Ceasar cipher that shifts the characters of the file that the user calls based on the shift amount that they input. For example if my file reads "hi" and they shift it by 1 it should read "ij". But when I run the program it doesnt recognize when I call in1 or out1 and I just get an error message. Can anyone help me figure out what I'm doing wrong or offer any advice on how to move forward? Thank you in advance!

#include <iostream>
#include <iomanip>
#include <fstream>
#include <cctype>
using namespace std;

int main()
{
    //Declare user variables
    int shift, file1chars = 0;
    char filename[25];
    ifstream in1;
    ofstream out1;

    do
    {
        in1.clear(); //clear status flags

        //Prompt user to enter name of input file and amount of shift
        cout << "Please enter the name of the input file." << endl;
        cout << "Filename: ";
        cin >> filename;

        //Open file name
        in1.open(filename);

        //Error message if no file
        if (!in1)
            cout << "That is not a valid file. Try again\n";

    } while (!in1);

    do
    {
        out1.clear(); //clear status flags
        //prompt user to input out file     
        cout << "Please enter the name of the output file." << endl;
        cout << "Filename: ";
        cin >> filename;

        out1.open(filename);
        //Error message if no file
        if (!out1)
            cout << "That is not a valid file. Try again\n";
    } while (!out1);

    //write some code to the input file 
    in1 >> "hi"

    //write the integers in a different order to the output file
    out1 << //idk where to go from here to initiate shift 

    //prompt user to enter shift
            cout << "Please intput the shift amount: ";
    cin >> shift;
    cout << "Processing complete" << endl;

    //Call file (?)

    //Tell user file input is complete and is now printing statistics
    cout << "\nShifted input file Complete. Now printing statistics " << endl;

    //Show statistics for file
    cout << "\nStatistics for file: " << filename << endl;
    cout << "------------------------------------------------";

    //Show characters in file and stats before shift
    cout << "\n\nTotal # of characters in file: " << file1chars << endl;
    cout << "Statistics before shift: " << endl;

    //Show file before shift

    //Show user stats after shift
    cout << "\nStatistics after shift: " << endl;

    //File after shift

    //Close files
    out1.close();
    in1.close();
    return 0;
}
user4581301
  • 33,082
  • 7
  • 33
  • 54
Holly Thorsted
  • 23
  • 1
  • 2
  • 6
  • Depending on the version of C++ you are using, you may need to use `in1.open(filename.c_str())`. – Thomas Matthews Mar 08 '18 at 23:00
  • you should `close` the stream after done with it. In the loop you open use the same output stream for opening multiple files without closing it. – Raindrop7 Mar 08 '18 at 23:03
  • please try to fix your formatting - your indenting is kind of out of control. – Joe Mar 08 '18 at 23:04
  • @ThomasMatthews: Class fstream overloaded new version of `open` to take a `class std::string` as its parameter instead of constant pointer to character string. – Raindrop7 Mar 08 '18 at 23:08
  • `in1 >> "hi"` attempts to read data from the file and store it into a constant array of characters. Because the array is constant, this will not work. I suspect you do not want to do this. May I suggest reading into a `std::string``? – user4581301 Mar 08 '18 at 23:08
  • *Can anyone help me figure out what I'm doing wrong or offer any advice on how to move forward?* When and where are you seeing problems? Compile time? Run time? Which lines of code? – R Sahu Mar 08 '18 at 23:09
  • The thing I can't get passed is when I run the program and it asks for file name I input in1 and I just get an error message and can't run the rest of my code. I'm not sure if I'm just not inputting the right filename since this is new to me or if I'm calling it wrong @RSahu – Holly Thorsted Mar 08 '18 at 23:09
  • @ThomasMatthews: The OP uses the same file stream objects on multiple files without closing it before each new use. – Raindrop7 Mar 08 '18 at 23:10
  • @Raindrop7: I'm aware of the modification. But again the question is *what version* of C++ was it placed in. I don't remember exactly. :-( – Thomas Matthews Mar 08 '18 at 23:11
  • By running you mean compiling, yes? Please provide the error message. – user4581301 Mar 08 '18 at 23:11
  • No fair, the code changed. Now the filename is an array of characters. – Thomas Matthews Mar 08 '18 at 23:12
  • @user4581301 it gives me my own error message and says "That is not a valid file. Try again" and no matter how many times I enter in1 or out1 nothing happens and yes I mean compiling – Holly Thorsted Mar 08 '18 at 23:14
  • OK. Had to check because the current code cannot compile. A common problem is using a relative file path inside an Integrated Development Environment (IDE). IDEs often run the program from a different folder than the executable. To eliminate this possibility you can use the full path of the file you want opened (you'll have to make `filename` bigger or use a `string`) or you can use the `getcwd` function to get where the program thinks it is and take this location into account. – user4581301 Mar 08 '18 at 23:19
  • Are you able to use `class` `structs` and `functions`? – Francis Cugler Mar 09 '18 at 03:26
  • I figured out it was because I was calling the file wrong, I have to say in1.txt in order to retrieve the file. Now I'm just working on the shifting part which is quite hard! – Holly Thorsted Mar 12 '18 at 20:12

2 Answers2

1

Instead of looking at your code for line by line to see where the problem(s) could be, I ask you to think about your requirements and write code that expresses the intent as closely as possible. Create functions that follow the intended functionality.

  1. Get the input file name.
  2. Get the output file name.
  3. Read the contents of the input file.
  4. Transform the contents of the input file to create the output string.
  5. Write the output string to the output file.

In pseudo code,

int main()
{
    infile = get_input_filename()
    outfile = get_output_filename()
    contents = get_file_contents(infile)
    output = transform_input(contents)
    write_output(outfile, output)
}

Convert that to C++ code:

// Declare the functions.

std::string get_input_filename();
std::string get_output_filename();
std::string get_file_contents(std::string const& infile)
std::string transform_input(std::string const& contents)j
void write_output(std::string const& outfile, std::string const& output);

// Use them in main.

int main()
{
    std::string infile = get_input_filename();
    std::string outfile = get_output_filename();
    std::string contents = get_file_contents(infile);
    std::string output = transform_input(contents);
    write_output(outfile, output);
}

// Implement the functions.

std::string get_input_filename()
{
    std::string filename;
    cout << "Please enter the name of the input file." << endl;
    cout << "Filename: ";
    cin >> filename;
    return filename;
}

std::string get_output_filename()
{
    std::string filename;
    cout << "Please enter the name of the output file." << endl;
    cout << "Filename: ";
    cin >> filename;
    return filename;
}

std::string get_file_contents(std::string const& infile)
{
   std::ifstream inf(infile);
   std::string contents;
   int c;
   while ( (c = inf.get()) != EOF )
   {
      contents += c;
   }
   return contents;
}

std::string transform_input(std::string const& contents)
{
   std::string res;
   // Do the needful to transform contents to res.
   return res;
}

void write_output(std::string const& outfile, std::string const& output)
{
   std::ofstream outf(outfile);
   outf.write(output.c_str(), output.size();
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
0

If you are able to use a class or struct and functions I would propose something like this:

main.cpp

#include <string>
#include <iostream>
#include <fstream>
#include "CaesarShift.h"

int main() {
    std::string filename;
    std::cout << "Please enter the name of the input file. ";
    std::cin >> filename;

    std::ifstream fileIn;
    std::string   text;

    fileIn.open( filename );
    if ( !fileIn.is_open() ) {
        std::cout << "Failed to open file: " << filename << "." << std::endl;
    }

    fileIn >> text;
    fileIn.close();

    CaesarText caesarText;
    caesarText.addText( text );    

    std::cout << "Contents of the Caesar Text before peforming a Caesar Shift:\n"
        << caesarText << std::endl;

    int amount = 0;
    std::cout << "Please enter the amount to shift the text ";
    std::cin >> amount;
    std::cout << "Now performing the Caesar Shift: " << std::endl;

    caesarShift( caesarText, amount );

    std::cout << "Caesar Text after performing a Caesar Shift:\n"
        << ceasarText << std::endl;

    std::ofstream fileOut;
    fileOut.open( std::string( "shifted_" + filename ) );
    if ( !fileOut.is_open() ) {
        std::cout << "Failed to open shifted_" << filename << std::endl;
    }
    // Uncomment to print original text to file otherwise only modified text will be printed.
    // fileOut << caesarText.originalText() << std::endl;
    fileOut << caesarText.shiftedText() << std::endl;
    fileOut.close();

    system( "PAUSE" );
    return 0;
}

CaesarShift.h

#ifndef CAESAR_SHIFT_H
#define CAESAR_SHIFT_H  

class CaesarText {
    std::string _originalText;
    std::string _shiftedText;

public:
    caesarText() = default;
    explicit CeasarText( const std::string& text ) :
        _originalText( text ) {}

    void addText( const std::string& text ) {
        _originalText = text;
    }

    std::string originalText() const {
        return _originalText;
    }

    std::string shiftedText() const {
        return _shiftedText;
    }

    friend void caesarShift( caesarText& c, int amount );    
    friend std::ostream& operator<<( std::ostream& out, const caesarText& ceasarText );
};

#endif // !CAESAR_SHIFT_H

CaesarShift.cpp

#include "CaesarShift.h"

#include <string>
#include <iostream>
#include <algorithm>

// Overloaded ostream operator
std::ostream& operator<<( std::ostream& o, const CaesarText& c ) {
    o << "Original Text: " << c._originalText << "\n";
    o << "Shifted Text: " << c._shiftedText << "\n";
    return o;
}

// public friend function (visible in main) not actually a part of the class
// but performs operations on it.
// To perform the Caesar Shift here are 3 possible variations of implementing the same task.
void caesarShift( Caesar Text& text, int amount ) {
    // Bound amount to the number of characters in the alphabet 
    // the same value used in any of the three variations below.
    amount %= 26;

    // Older c++ style loop.
    /*for ( std::size_t i = 0; i < text._originalText.length(); i++ ) {
        char c = text._originalText[i] + amount;
        text._shiftedText += c;
    }*/

    // Modern C++ style loop
    /*for ( auto& c : text._originalText ) {
        text._shiftedText += c + amount;
    }*/

    // std::transform( s1.begin, s1.end, back_inserter( s2 ), lamda as predicate );
    /*std::transform( text._originalText.begin(), text._originalText.end(),
                std::back_inserter( text._shiftedText ),
                [amount]( unsigned char c ) -> unsigned char { return c + amount; }
    );*/    
}

As for the 3 different variations of performing the Caesar Shift you can just uncomment the appropriate block section.

Francis Cugler
  • 7,788
  • 2
  • 28
  • 59