mercredi 2 août 2017

terminate called after throwing an instance of 'std::out_of_range' - Should be easy to resolve

For my introductory C++ class I was tasked with completing this program, which uses file I/O to encode and decrypt text using a cypher.

Most of the function definitions were written by me while everything else was written by my professor. I think the program should work (if it would compile) but I am getting the following error:

terminate called after throwing an instance of 'std::out_of_range' what(): basic_string::at: __n (which is 0) >= this->size() (which is 0) bash: line 12: 5645 Aborted $file.o $args

I believe this is a very common problem and should be easy to resolve. However, I am a beginner and am not sure how to interpret this seemingly common error message. The "out of range" leads me to believe that maybe it's a problem with the loops I wrote to iterate through strings (for example, in the function RotateCipherKey()?) that don't work if the string is of zero length? Hopefully, someone can recognize the problem.

Thank you for the help. Here is my code:

#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <cctype>

using namespace std;

class Crypto {
public:
    void DisplayFile(string filename);
    void EncryptFile(string cipher_key, string filename_from, string filename_to);
    void DecryptFile(string cipher_key, string filename_from, string filename_to);
    string EncryptString(string &cipher_key, string string_to_be_encrypted);
    string DecryptString(string &cipher_key, string string_to_be_decrypted);
private:
    string cipher_key;
    void RotateCipherKey();
    char substitution_cipher(char char_to_encrypt);
    char reverse_substitution_cipher(char char_to_encrypt);
};

using namespace std;

//  Rotate the cipher key. Example: abcdef becames bcdefa
//
// Note: Call by reference
void Crypto::RotateCipherKey()
{
    int bound = 0;
    if(cipher_key.length() > 0)
        bound = cipher_key.length()-1;
    char char_to_rotate = cipher_key.at(0);
    int i = 0;

    for(i=0; i<bound; i++){
        cipher_key.at(i) = cipher_key.at(i+1);
    }

    cipher_key.at(bound) = char_to_rotate;
}

// Perform a substitution cipher on a single character
// using the specified cipher key
// make sure it is lowercase (switch it if not) and an alpha
// character

char Crypto::substitution_cipher(char char_to_encrypt)
{
    int cipherLength=0, i=0;

    if(!islower(char_to_encrypt))
        char_to_encrypt = tolower(char_to_encrypt);

    if(!isalpha(char_to_encrypt)){
        cout << "Character to encrypt must be alphabetical!";
        return char_to_encrypt;
    }

    cipherLength = cipher_key.length();

    for(i=0; i<cipherLength; i++){
        RotateCipherKey();
        char_to_encrypt = cipher_key[i];
        }

    return char_to_encrypt;
}


// Perform a "reverse" substitution cipher on a single character
// using the specified cipher key
// See reference document for implementation details.
// You reverse the operation described above

char Crypto::reverse_substitution_cipher(char char_to_decrypt)
{
    int i=0, cipherLength=0;
    cipherLength = cipher_key.length();

    for(i=0; i<cipherLength; i++){
        RotateCipherKey();
        char_to_decrypt = cipher_key[i];
    }

    return char_to_decrypt;
}

// Encrypt String and return it
// You will use the substitution_cipher() function to encrypt the
// individual characters
//
// Think for loop
string Crypto::EncryptString(string &cipher_key, 
    string string_to_be_encrypted)
{
    int i=0, loopBound=0;
    char tempChar;
    if(string_to_be_encrypted.length()>0)
        loopBound=string_to_be_encrypted.length();

    for(i=0; i < loopBound; i++){
        tempChar = substitution_cipher(string_to_be_encrypted[i]);
        RotateCipherKey();
    }

    string encrypted_string = string_to_be_encrypted;
    cout << " " << string_to_be_encrypted;
    return encrypted_string;
}

// Decrypt String and return it
// You will use the reverse_subsitution_cipher() function to 
// decrypt the individual characters
//
string Crypto::DecryptString(string &cipher_key, string string_to_be_decrypted)
{
    string decrypted_string = string_to_be_decrypted;

    return decrypted_string;
}

//
// Need to finish this one
//
// Display file specified by the filname parameter
// See EncryptFile/DecryptFile for details on how to read and
// display a file. Use the ifstream infile section to read a file
// and cout to display it to the screen.
void Crypto::DisplayFile(string filename)
{
    string tempString;
    ifstream infile;
    infile.open(filename);

    infile >> tempString;
    while(infile){
        cout << " " << tempString;
        infile >> tempString;
    }

    cout << endl;
}

// Encrypt the specified file using the specified cipher key and
// write the output to a different file
// This function is complete
void Crypto::EncryptFile(string cipher_key, 
    string filename_from, string filename_to)
{
    string input;
    ifstream infile;
    ofstream outfile;

    infile.open (filename_from.c_str());
    outfile.open (filename_to.c_str());

    if(!infile)
    {
        cout << "Can not open input file " + filename_from << endl;
        exit(0);
    }

    if(!outfile)
    {
        cout << "Can not open Output file " + filename_to << endl;
        exit(0);
    }


    while( getline(infile, input))
    {
        outfile << EncryptString(cipher_key,  input) << endl;
    }
    infile.close();
    outfile.close();
}

// Decrypt the specified file using the specified cipher key and
// write the output to a different file
// This function is complete
void Crypto::DecryptFile(string cipher_key, 
    string filename_from, string filename_to)
{
    string input;
    ifstream infile;
    ofstream outfile;

    infile.open (filename_from.c_str());
    outfile.open (filename_to.c_str());

    if(!infile)
    {
        cout << "Can not open input file " + filename_from << endl;
        exit(0);
    }

    if(!outfile)
    {
        cout << "Can not open Output file " + filename_to << endl;
        exit(0);
    }


    while( getline(infile, input))
    {
        outfile << DecryptString(cipher_key,  input) << endl;
    }
    infile.close();
    outfile.close();
}

int main()
{
    Crypto Cipher1;
    Crypto Cipher2;
    string cipher_key = "qwertyuiopasdfghjklzxcvbnm";
    string cipher_key2 = "wertyuiopasdgfhjqklzxcvbnm";

    Cipher1.EncryptFile(cipher_key, "test.txt",
                        "test-encrypted.txt");
    Cipher1.DecryptFile(cipher_key, "test-encrypted.txt",
                        "test-encrypt-decrypt-test.txt");
    Cipher1.DisplayFile("test.txt");
    Cipher1.DisplayFile("test-encrypted.txt");
    Cipher1.DisplayFile("test-encrypt-decrypt-test.txt");

    string cipher_key3 = cipher_key2;
    cout << Cipher2.EncryptString(cipher_key3,
        "C++ Programming Is Fun") << endl;

    cipher_key3 = cipher_key2;
    string cipher_key4 = cipher_key2;

    cout << Cipher2.DecryptString(cipher_key2, 
        Cipher2.EncryptString(cipher_key3,"C++ Programming Is Fun") )
     << endl;

    return 0;
}

Aucun commentaire:

Enregistrer un commentaire