Vector is out of range - c++

A good day to all stackers.
I am running my program in Quincy2005 and I have this following error.
"Terminate called after throwing an instance of 'std::out_of_range"
"what(): vector::_M_range_check"
The below is my bunch of codes
int ptextLoc,ctextLoc; //location of the plain/cipher txt
char ctextChar; //cipher text variable
//by default, the location of the plain text is even
bool evenNumberLocBool = true;
ifstream ptextFile;
//open plain text file
ptextFile.open("ptext.txt");
//character by character encryption
while (!ptextFile.eof())
{
//get (next) character from file and store it in a variable ptextChar
char ptextChar = ptextFile.get();
//find the position of the ptextChar in keyvector Vector
ptextLoc = std::find(keyvector.begin(), keyvector.end(), ptextChar) - keyvector.begin();
//if the location of the plain text is even
if ( ((ptextLoc % 2) == 0) || (ptextLoc == 0) )
evenNumberLocBool = true;
else
evenNumberLocBool = false;
//if the location of the plain text is even/odd, find the location of the cipher text
if (evenNumberLocBool)
ctextLoc = ptextLoc + 1;
else
ctextLoc = ptextLoc - 1;
//store the cipher pair in ctextChar variable
ctextChar = keyvector.at(ctextLoc);
cout << ctextChar;
}
Contents of ptext.txt
ab cd ef
If the first letter is 'a' which is at the position 0, the pair cipher alphabet will be kevector[1].
LATEST UPDATE: I have found the line which has been creating this error.
ctextChar = keyvector.at(ctextLoc);
However, I am not sure why is it happening with this line.
I hope someone will be able to guide me.

if (ctextLoc > keyvector.size())
should probably be
if (ctextLoc >= keyvector.size())

std::vector's size() returns a value 1 --- N, where as at() relies on values 0 --- (N - 1). Therefore, you should use:
if (keyvector.size() != 0 && ctextLoc > keyvector.size() - 1)
break;

Related

How to input a multi-digit integer into an Arduino using a 4x4 keypad?

I am trying to make a combination lock using an Arduino, a keypad and a Servo but I have come across an obstacle.
I can't find a way to store a 4 digit value in a variable. since keypad.getKey only allows to store one digit.
After some browsing on the internet I came upon a solution for my problem on a forum but the answer didn't include a code sample, and I couldn't find anything else about in on the internet.
The answer said to either use a time limit for the user to input the number or a terminating character (which would be the better option according to them).
I would like to know more bout these terminating characters and how to implement them, or if anybody could suggest a better solution that would be much appreciated as well.
Thank you in advance,
To store 4 digit values, the easiest and naive way to do it is probably to use an array of size 4. Assuming keypad.getKey returns an int, you could do something like this: int input[4] = {0};.
You will need a cursor variable to know into which slot of the array you need to write when the next key is pressed so you can do some kind of loop like this:
int input[4] = {0};
for (unsigned cursor = 0; cursor < 4; ++cursor) {
input[cursor] = keypad.getKey();
}
If you want to use a terminating character (lets say your keyboard have 0-9 and A-F keys, we could say the F is the terminating key), the code changes for something like:
bool checkPassword() {
static const int expected[4] = {4,8,6,7}; // our password
int input[4] = {0};
// Get the next 4 key presses
for (unsigned cursor = 0; cursor < 4; ++cursor) {
int key = keypad.getKey();
// if F is pressed too early, then it fails
if (key == 15) {
return false;
}
// store the keypress value in our input array
input[cursor] = key;
}
// If the key pressed here isn't F (terminating key), it fails
if (keypad.getKey() != 15)
return false;
// Check if input equals expected
for (unsigned i = 0; i < 4; ++i) {
// If it doesn't, it fails
if (expected[i] != input[i]) {
return false;
}
}
// If we manage to get here the password is right :)
return true;
}
Now you can use the checkPassword function in your main function like this:
int main() {
while (true) {
if (checkPassword())
//unlock the thing
}
return 0;
}
NB: Using a timer sounds possible too (and can be combined with the terminating character option, they are not exclusive). The way to do this is to set a timer to the duration of your choice and when it ends you reset the cursor variable to 0.
(I never programmed on arduino and don't know about its keypad library but the logic is here, its up to you now)
In comment OP says a single number is wanted. The typical algorithm is that for each digit entered you multiply an accumulator by 10 and add the digit entered. This assumes that the key entry is ASCII, hence subtracting '0' from it to get a digit 0..9 instead of '0'..'9'.
#define MAXVAL 9999
int value = 0; // the number accumulator
int keyval; // the key press
int isnum; // set if a digit was entered
do {
keyval = getkey(); // input the key
isnum = (keyval >= '0' && keyval <= '9'); // is it a digit?
if(isnum) { // if so...
value = value * 10 + keyval - '0'; // accumulate the input number
}
} while(isnum && value <= MAXVAL); // until not a digit
If you have a backspace key, you simply divide the accumulator value by 10.

iterating vector of strings C++

The code is to read instructions from text file and print out graphic patterns. One is my function is not working properly. The function is to read the vectors of strings I've got from the file into structs.
Below is my output, and my second, third, and sixth graphs are wrong. It seems like the 2nd and 3rd vectors are not putting the correct row and column numbers; and the last one skipped "e" in the alphabetical order.
I tried to debug many times and still can't find the problem.
typedef struct Pattern{
int rowNum;
int colNum;
char token;
bool isTriangular;
bool isOuter;
}Pattern;
void CommandProcessing(vector<string>& , Pattern& );
int main()
{
for (int i = 0; i < command.size(); i++)
{
Pattern characters;
CommandProcessing(command[i], characters);
}
system("pause");
return 0;
}
void CommandProcessing(vector<string>& c1, Pattern& a1)
{
reverse(c1.begin(), c1.end());
string str=" ";
for (int j = 0; j < c1.size(); j++)
{
bool foundAlpha = find(c1.begin(), c1.end(), "alphabetical") != c1.end();
bool foundAll = find(c1.begin(), c1.end(), "all") != c1.end();
a1.isTriangular = find(c1.begin(), c1.end(), "triangular") != c1.end() ? true : false;
a1.isOuter = find(c1.begin(), c1.end(), "outer") != c1.end() ? true : false;
if (foundAlpha ==false && foundAll == false){
a1.token = '*';
}
//if (c1[0] == "go"){
else if (c1[j] == "rows"){
str = c1[++j];
a1.rowNum = atoi(str.c_str());
j--;
}
else if (c1[j] == "columns"){
str = c1[++j];
a1.colNum = atoi(str.c_str());
j--;
}
else if (c1[j] == "alphabetical")
a1.token = 0;
else if (c1[j] == "all"){
str = c1[--j];
a1.token = *str.c_str();
j++;
}
}
}
Before debugging (or posting) your code, you should try to make it cleaner. It contains many strange / unnecessary parts, making your code harder to understand (and resulting in the buggy behaviour you just described).
For example, you have an if in the beginning:
if (foundAlpha ==false && foundAll == false){
If there is no alpha and all command, this will be always true, for the entire length of your loop, and the other commands are all placed in else if statements. They won't be executed.
Because of this, in your second and third example, no commands will be read, except the isTriangular and isOuter flags.
Instead of a mixed structure like this, consider the following changes:
add a default constructor to your Pattern struct, initializing its members. For example if you initialize token to *, you can remove that if, and even the two bool variables required for it.
Do the parsing in one way, consistently - the easiest would be moving your triangular and outer bool to the same if structure as the others. (or if you really want to keep this find lookup, move them before the for loop - you only have to set them once!)
Do not modify your loop variable ever, it's an error magnet! Okay, there are some rare exceptions for this rule, but this is not one of them.
Instead of str = c1[++j];, and decrementing later, you could just write str = c1[j+1]
Also, are you sure you need that reverse? That makes your relative +/-1 indexing unclear. For example, the c1[j+1 is j-1 in the original command string.
About the last one: that's probably a bug in your outer printing code, which you didn't post.

Array of characters copy error

My question is this, when the inner for loop exits, and enters back into the outer for loop it stops adding characters to the string pointer pstrDestination. Can some one explain that to me, I am not terminating the array of character so it should still write, shouldn't it?
// Does it match
if (strcmp(strCompareString, pstrToFind) == 0)
{
// Reset the index of the found letter
intFoundLetterIndex = (intFoundLetterIndex - intCompareIndex);
// Add the characters from source to destination.
for (intSourceIndex = 0; intSourceIndex < intSourceLength; intSourceIndex += 1)
{
pstrDestination[intDestinationIndex] = pstrSource[intSourceIndex];
intDestinationIndex += 1;
// Are we at the beginning of the target word
if (intSourceIndex == intFoundLetterIndex)
{
// Add the replacement characters to the destination.
for (intNewIndex = 0; intNewIndex < intReplaceWithLength; intNewIndex += 1)
{
pstrDestination[intDestinationIndex - 1] = pstrReplaceWith[intNewIndex];
intDestinationIndex += 1;
}
intSourceIndex += intToFindLength;
}
}
}
I think this
intDestinationIndex - 1;
should look like this:
intDestinationIndex -= 1;
Best I can come up with is, The Visual Studio 2013 IDE is trying to give me a huge big ol' hug.
It is terminating the string for me.
if I step the index back 1 and set the spot in the array equal to ' '. Then the loop executes as expected cause I over wrote the terminator.
after the inner loop I added;
pstrDestination[intDestinationIndex - 1] = ' ';

Converting scancodes to ASCII

I'm implementing my own text editor in c++. It's going... ok. ;P
I need a way to turn a keycode (specifically Allegro, they call it scancodes) into an ASCII-char. I can do A-Z easy, and converting those to a-z is easy as well. What I do currently is use a function in Allegro that returns a name from a scancode (al_keycode_to_name), meaning if the key pressed is A-Z it returns "A" to "Z". That's easy peasy, but I can't simply read special characters like ",", ";" etc. That's where I'm having a hard time.
Is there a way to do this automatically? Maybe a library that does this? The real trick is taking different layouts into consideration.
Here's what I have so far, in case anyone's interested. The class InputState is basically a copy of the Allegro inputstate, with added functionality (keyDown, keyUp, keyPress for example):
void AllegroInput::TextInput(const InputState &inputState, int &currentCharacter, int &currentRow, std::string &textString)
{
static int keyTimer = 0;
static const int KEY_TIMER_LIMIT = 15;
for (int i = 0; i < 255; i++)
{
if (inputState.key[i].keyDown)
{
keyTimer++;
}
if (inputState.key[i].keyPress)
{
keyTimer = 0;
}
if ((inputState.key[i].keyPress) || ((inputState.key[i].keyDown) && (keyTimer >= KEY_TIMER_LIMIT)))
{
std::string ASCII = al_keycode_to_name(i);
if ((ASCII.c_str()[0] >= 32) && (ASCII.c_str()[0] <= 126) && (ASCII.length() == 1))
{
textString = textString.substr(0, currentCharacter) + ASCII + textString.substr(currentCharacter, textString.length());
currentCharacter++;
}
else
{
switch(i)
{
case ALLEGRO_KEY_DELETE:
if (currentCharacter >= 0)
{
textString.erase(currentCharacter, 1);
}
break;
case ALLEGRO_KEY_BACKSPACE:
if (currentCharacter > 0)
{
currentCharacter--;
textString.erase(currentCharacter, 1);
}
break;
case ALLEGRO_KEY_RIGHT:
if (currentCharacter < textString.length())
{
currentCharacter++;
}
break;
case ALLEGRO_KEY_LEFT:
if (currentCharacter > 0)
{
currentCharacter--;
}
break;
case ALLEGRO_KEY_SPACE:
if (currentCharacter > 0)
{
textString = textString.substr(0, currentCharacter) + " " + textString.substr(currentCharacter, textString.length());
currentCharacter++;
}
break;
}
}
}
}
}
You should be using the ALLEGRO_EVENT_KEY_CHAR event with the event.keyboard.unichar value to read text input. ALLEGRO_EVENT_KEY_DOWN and ALLEGRO_EVENT_KEY_UP correspond to physical keys being pressed. There is not a 1:1 correspondence between them and printable characters.
Say a dead key is being used to convert the two keys e' to é. You'd get two key down events for e and ' (and neither are useful for capturing the proper input), but one key char event with é. Or inversely, maybe somebody mapped F4 to a macro that unleashes an entire paragraph of text. In that case, you'd have multiple chars for a single key down.
Or a simple test: if you hold down a key for five seconds, you will get one ALLEGRO_EVENT_KEY_DOWN but multiple ALLEGRO_EVENT_KEY_CHAR as the OS' keyboard driver sends repeat events.
You can use ALLEGRO_USTR to easily store these unicode strings.
ALLEGRO_USTR *input = al_ustr_new("");
// in the event loop
al_ustr_append_chr(input, event.keyboard.unichar);
There's also ways to delete characters if backspace is pressed, etc. You can use the ustr data types with the font add-on directly via al_draw_ustr(font, color, x, y, flags, input), or you can use al_cstr(input) to get a read-only pointer to a UTF-8 string.

input string validation without external libraries for c++

I need to validate one input string from a user. Eventually it will need to break down into two coordinates. ie a4 c3. And once they are coordinates they need to be broken out into 4 separate ints. a=0 b=1, etc. They must also follow the following stipulations:
If an end-of-input signal is reached the program quits.
Otherwise, all non-alphanumeric characters are discarded from the input.
If what remains is the single letter 'Q'
Then the program quits.
If what remains consists of 4 characters, with one letter and one digit among the first two characters and one letter and one digit among the last two characters, and if each letter-digit pair is in the legal range for our grid
Then input is acceptable.
I have completely over-thought and ruined my function. Please let me know where I can make some corrections.
I am mainly having trouble going from one string, to four chars if and only if the data is valid. Everything else I can handle.
Here is what I have so far.
void Grid::playerMove()
{
string rawMove;
string pair1 = " ";
string pair2 = " ";
bool goodInput = false;
char maxChar = 'a';
char chary1, chary2;
int x11,x22,y11,y22;
for (int i =0; i<size; i++)
{
maxChar++;
}
while(!goodInput)
{
cout<<"What two dots would you like to connect? (Q to quit) ";
cin>>rawMove;
rawMove = reduceWords(rawMove);
if (rawMove == "Q")
{
cout<<"end game";
goodInput = false;
}
else if (rawMove.size() == 4)
{
for(int j=0;j<2;j++)
{
if (pair1[j] >='a' && pair1[j] <=maxChar)
{
chary1 = pair1[j];
}
else if(pair1[j] >=0 && pairl[j]<=size+1)
{
x1 = pair1[j];
}
}
for(int k=0;k<2;k++)
{
if (pair2[k] >='a' && pair2[k] <=maxChar)
{
chary2 = pair2[k];
}
else if(pair2[k] >=0 && pair2[k]<=size+1)
{
x2 = pair2[k];
}
}
}
if(char1 != NULL && char2 != NULL && x1 !=NULL && x2 != NULL)
{
for (int m = 0; m <= size m++)
{
if (char1 == m;)
{
x1 = m;
}
}
for (int n = 0; n <= size n++)
{
if (char2 == n)
{
x2 = n;
}
}
}
}
The end goal would be to have x1, x2, y1, and y2 with their respective values.
Keep in mind I am not allowed to have any external libraries.
It's not clear what exactly you want to achieve, but here are some pointers to get you started:
The while loop will never end because you're setting goodInput to false on quit which lets the loop continue.
The code probably does not even compile? You are missing a curly closing brace..
You are initializing pair1 and pair2 to empty strings but never change them again, so they will never contain any real information about your moves
maybe what you really want is to split up rawMove into the pair1 and pair2 substrings first?
Since this is a homework - and you're supposed to learn from those (right?) - I'm not going to give you the complete answer, but rather something like a recipe:
Use std::istream::getline(char*, std::streamsize s) to read a whole line from std::cin. Make sure you allocate a buffer large enough to hold the expected input (including the terminating null character) plus some more for invalid characters. After the call, check the failbit (input was too long) and the eofbit (hit the end-of-input) of the std::cin stream and handle those cases. Construct a std::string from the buffer if there was no error or EOF has not been reached.
Write a character-classification function (e.g. call it isAlNum(char c)) that returns true if the char argument is alpha-numeric, and false otherwise.
Combine std::string::erase(), std::remove_if(), std::not1(), std::ptr_fun() and your function isAlNum() to sanitise the input string.
Write a function that validates and parses the coordinates from the sanitised input string and call it with the sanitised input string.
Wrap the whole thing in an appropriate while() loop.
This should get you started in the right direction. Of course, if you're allowed to use C++11 features and you know how to write good regular expressions, by all means, use the <regex> header instead of doing the parsing manually.