Derrick Kwan
Derrick Kwan

Reputation: 1

Question - c++ terminate called after throwing an instance of 'std::out_of_range' what(): basic_string::substr:?

I'm new to coding and trying to create a program to encrypt/decrypt based on a map of 26 characters. The encryption part of the code works, but whenever I try to decrypt, I get the error

terminate called after throwing an instance of 'std::out_of_range'
  what():  basic_string::at: __n (which is 122) >= this->size() (which is 5).

What should I do?

#include <iostream>
#include <cstring>
using namespace std;

string encrypt(string word, string map = "zyxwvutsrqponmlkjihgfedcba") {
    string output = "";
    for(int i = 0; i < word.length(); i++) {
        int pos = word.at(i) - 'a';
        output += map.at(pos);
    }
    return output;
}

string decrypt(string word, string map = "zyxwvutsrqponmlkjihgfedcba") {
    string output = "";
    for(int i = 0; i < word.length(); i++) {
        int pos = map.at(i);
        output += word.at(pos) + 'a';
    }
    return output;
}

int main() {
    string method, word, map;
    cout << "What is the method (encryption or decryption)? ";
    cin >> method;
    if(method.compare("encryption") != 0 && method.compare("decryption") != 0) {
        cout << "Error: invalid method choice.\n";
        return 0;
    }
    cout << "What is the translation map (type 'default' to use default): ";
    cin >> map;
    if(map.compare("default") && method.length() != 26) {
        cout << "Error: invalid translation map size.\n";
        return 0;
    }
    cout << "What is the single word to translate: ";
    cin >> word;
    if(method.compare("encryption") == 0) {
        for(int i = 0; i < word.length(); i++)
            if(!isalpha(word.at(i)) || !islower(word.at(i))) {
                cout << "Error: encryption cannot be performed.\n";
                return 0;
            }
        if(map.compare("default") == 0)
            cout << "Encrypted word: " << encrypt(word) << endl;
        else
            cout << "Encrypted word: " << encrypt(word, map) << endl;
    }
    if(method.compare("decryption") == 0) {
        if(map.compare("default") == 0)
            map = "zyxwvutsrqponmlkjihgfedcba";
        for(int i = 0; i < word.length(); i++)
            if(map.find(word.at(i)) == string::npos) {
                cout << "Error: decryption cannot be performed." << endl;
                return 0;
            }
        if(map.compare("default") == 0)
            cout << "Decrypted word: " << decrypt(word) << endl;
        else
            cout << "Decrypted word: " << decrypt(word, map) << endl;
    }
}

Upvotes: 0

Views: 206

Answers (1)

Jasper Kent
Jasper Kent

Reputation: 3676

Looks like you're misunderstanding the meaning of string::at.

Consider the lines:

int pos = map.at(i);
output += word.at(pos) + 'a';

at simply gives you back the ASCII value of the character at position i in the string. Supposing i is zero, this is 'z' which has an ASCII value of 122.

You then try to look up the character at position 122 in word, word does not have that many characters. I'm not sure exactly what you're trying to do, but it's not that.

Upvotes: 3

Related Questions