-1

I understand that questions with this title/problem have been asked numerous times before (here,here and many others). Here is my code followed by what all I have done to remove the error:

CaesarCipher.h

#ifndef CAESARCIPHER_H
#define CAESARCIPHER_H

#include <ctime> 
#include <string>

using namespace std;

// Write your class CaesarCipher here.
class CaesarCipher 
{
public:
    CaesarCipher();
    string Encode(string plainString);
    string Decode(string encryptedString);
private:
    int key1, key2;
    char Encode(char normalChar)const;
    char Decode(char encodedChar)const;
};
#endif

CaesarCipher.cpp

#include "stdafx.h"
#include "CaesarCipher.h"

using namespace std;
// Implement the member functions of class CaesarCipher.

CaesarCipher::CaesarCipher()
{
    //Random initialization of integer key1

    //srand(time(0));
    srand((unsigned int)time(0));       
    int value1 = rand() % 10;
    int sign1 = rand() % 2;
    sign1 = sign1 == 0 ? -1 : 1;
    int key1 = value1 * sign1;

    //Random initialization of integer key2

    //srand(time(0));
    srand((unsigned int)time(0));
    int value2 = rand() % 10;
    int sign2 = rand() % 2;
    sign2 = sign2 == 0 ? -1 : 1;
    int key2 = value2 * sign2;
}

char CaesarCipher::Encode(char normalChar) const
{
    int result=0;
    int charValue = normalChar; //get the ASCII decimal value of character
    if (charValue == 32)        // if characeter is a space, we leave it 
{
    result = 32;
}
else
{
    if (key1 > 0)
    {
        result = char(int(charValue + key1 - 97) % 26 + 97);        // find the integer value of char after rotating it with key1(positive)
    }
    if (key1 < 0)
    {
        result = char(int(charValue -key1 - 97) % 26 + 97);         // find the integer value of char after rotating it with key1(negative)
    }
    if (key2 > 0)
    {
        result += char(int(charValue + key2 - 97) % 26 + 97);       // find the updated integer value of char after rotating it with key2(positive)
    }
    if (key2 < 0)
    {
        result += char(int(charValue - key2 - 97) % 26 + 97);       // find the updated integer value of char after rotating it with key2(negative)
    }
}
return result;                                  // returning the integer value which will be typecasted into a char(encoded char)
}

char CaesarCipher::Decode(char encodedChar) const
{
    int result = 0;
    int charValue = encodedChar; //get the ASCII decimal value of encoded character
    if (charValue == 32)        // if characeter is a space, we leave it unchanged
    {
        result = 32;
    }
    else
    {
        if (key1 > 0)
        {
            result = char(int(charValue - key1 - 97) % 26 + 97); // find the integer value of encoded char after rotating it with key1(positive) in opposite direction
        }
        if (key1 < 0)
        {
            result = char(int(charValue + key1 - 97) % 26 + 97); // find the integer value of encoded char after rotating it with key1(negative) in opposite direction
        }
        if (key2 > 0)
        {
            result += char(int(charValue - key2 - 97) % 26 + 97);       // find the updated integer value of encoded char after rotating it with key2(positive) in opposite direction
        }
        if (key2 < 0)
        {
            result += char(int(charValue + key2 - 97) % 26 + 97);       // find the updated integer value of encoded char after rotating it with key2(negative) in opposite direction
        }
    }
    return result;                                  // returning the integer value which will be typecasted into a char(decrypted char)
}

string CaesarCipher::Encode(string plainString)
{
    int length = plainString.length();          //gets the length of the 
    input string
    string encodedString;                       // variable to hold the final encrypted string
    for (int i = 0; i < length; i++)
    {
        encodedString[i] = Encode(plainString[i]); // encrypting the string one character at a time
    }
    return encodedString;                           // return the final encoded string
}

string CaesarCipher::Decode(string encryptedString)
{
    int length = encryptedString.length();  //gets the length of the input encrypted string
    string decodedString;                   // variable to hold the final decrypted string
    for (int i = 0; i < length; i++)
    {
        decodedString[i] = Decode(encryptedString[i]);      // decrypting the string one character at a time
    }
    return decodedString;                                   // return the final decoded string
}

I am using two keys to cipher the text (key1 followed by key2), if it helps in any way.

Main.cpp

#include "stdafx.h"
#include "CaesarCipher.h"
#include <fstream>
#include <iostream>

int main() {
    // File streams
    ifstream fin("input.txt");
    ofstream fout("output.txt");

    if (!fin.good()) {
        cout << "Error: file \"input.txt\" does not exist!" << endl;
        return -1;
    }

    string original[20], encrypted[20], decrypted[20];
    int i = 0;      // will store the number of lines in the input file
    CaesarCipher cipher;    // an object of CaesarCipher class
    // Read the sentences from the input file and save to original[20].
    // Hint: use getline() function.
    while (!fin.eof())
    {
        getline(fin, original[i]);                      // Reading a line from input.txt file 
        encrypted[i] = cipher.Encode(original[i]);      // Encrypt the sentences and save to encrypted[20]
        decrypted[i] = cipher.Decode(encrypted[i]);     // Decrypt the sentences and save to decrypted[20]
        i++;
    } 

    //first output all the encrypted lines
    for (int j = 0; j < i; j++)
    {
        fout << "Encrypted sentences:\n";
        fout << encrypted[j]<<"\n";
    }

    //now output all the decrypted lines
    for (int j = 0; j < i; j++)
    {
        fout << "Decrypted sentences:\n";
        fout << decrypted[j] << "\n";
    }

    // Close the files and end the program.
    fin.close();
    fout.close();
    cout << "done!";
    return 0;
}

The error which i am getting isExpression: string subscript out of range. Now i understand that i am trying to iterate beyond the limits of the string (somewhere probably in CaesarCipher.cpp in Encoder or Decoder function).

I have tried to change the limits on i without any effect.

I have tried to use size() instead of length() (in desperacy inspite knowing they do the same thing).

I would really appreciate if you can pin-point any thing in particular which might be causing this error and i will try and change it by myself and see the results.

And if you can also tell, how to avoid such errors in future that will also be of great value to me.

  • There appears to be way too much code here. What have you observed from hitting _Retry_ on the exception in your debugger, and viewing the call stack? – Tas Sep 20 '17 at 02:55

1 Answers1

0

CaesarCipher::Encode() is not allocating any memory for the character data of encodedString, so the loop has nothing valid to access with encodedString[i]. To fix that, either:

  1. Use string encodedString = plainString; to make a copy of the input string, then the loop can manipulate the copied data:

    string CaesarCipher::Encode(string plainString) {
        int length = plainString.length(); //gets the length of the input string
        string encodedString = plainString; // variable to hold the final encrypted string
        for (int i = 0; i < length; i++) {
            encodedString[i] = Encode(encodedString[i]); // encrypting the string one character at a time
        }
        return encodedString; // return the final encoded string
    } 
    
  2. Use encodedString.resize(length) to pre-allocate the output string before entering the loop:

    string CaesarCipher::Encode(string plainString) {
        int length = plainString.length(); //gets the length of the input string
        string encodedString; // variable to hold the final encrypted string
        encodedString.resize(length); // allocate memory for the final encoded string
        for (int i = 0; i < length; i++) {
            encodedString[i] = Encode(plainString[i]); // encrypting the string one character at a time
        }
        return encodedString; // return the final encoded string
    } 
    
  3. Use encodedString += plainString[i]; to append characters to the output string and let it grow as needed:

    string CaesarCipher::Encode(string plainString) {
        int length = plainString.length(); //gets the length of the input string
        string encodedString; // variable to hold the final encrypted string
        for (int i = 0; i < length; i++) {
            encodedString += Encode(plainString[i]); // encrypting the string one character at a time
        }
        return encodedString; // return the final encoded string
    } 
    

The same problem exists in CaesarCipher::Decode() with the decodedString variable.


Also, main() has a buffer overflow if input.txt has more than 20 lines in it. Consider changing the code to use std::vector instead of fixed arrays.

And while (!fin.eof()) is wrong to use. Use while (getline(...)) instead:

// Read the sentences from the input file and save to original[20].
// Hint: use getline() function.
string line;
while (getline(fin, line)) { // Reading a line from input.txt file
    original[i] = line;
    encrypted[i] = cipher.Encode(original[i]); // Encrypt the sentences and save to encrypted[20]
    decrypted[i] = cipher.Decode(encrypted[i]); // Decrypt the sentences and save to decrypted[20]
    i++;
} 
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I tried the `encodedString.resize(length)` thing and it is working(compiling). Can you share how you figured out no memory allocation? Secondly, I also had the thought of using vectors but its part of the description of assignment to use arrays and the input file will not contain more than 20 lines so I think I can ignore the buffer overflow issue(for this particular instance) – Piyush Menghani Sep 20 '17 at 07:51
  • @PiyushMenghani `string encodedString;` default-constructs the `string` with no data in it. Thus `encodedString[i]` tries to access a character that does not exist. – Remy Lebeau Sep 20 '17 at 14:59