Expression: string subscript out of range. Attribute passing issue? - c++

I am running into an error during my program's runtime:
"Debug Assertion Failed! ... Expression: string subscript out of range."
This is happening in my for loop when my if statement attempts to check if the character at 'i' in the string isDelimiter() or isOperator(). I am passing the char 'check' as an attribute, and in the comments I have made sure that 'check' is grabbing the correct character. I've been working on this issue for a while and I can't seem to resolve it.
EDITED AT BOTTOM
string inputLine = "";
string inputString = "";
int main()
{
ifstream input("input.txt");
getline(input, inputLine);
if (input.is_open())
{
while (!input.eof())
{
getline(input, inputLine);
for (int i = 0; i<inputLine.length(); i++)
{
char check = inputLine[i];
//cout << check << "\n"; // test for correct character
if ((inputLine[i] != ' ') || (inputLine[i] != isDelimiter(check)) || (inputLine[i] != isOperator(check)))
{
inputString = inputString + inputLine[i];
//cout << lexer(inputString) << "\n";
//cout << inputString;
} // end if
else
{
cout << lexer(inputString);
if (inputLine[i] == isDelimiter(i))
cout << inputLine[i] + "\tDELIMITER";
if (inputLine[i] == isOperator(i))
cout << inputLine[i] + "\tOPERATOR";
inputString = "";
} // end else
//cout << inputString << "\n";
} // end for
} // end while
//input.close();
}
else cout << "Unable to open file.";
return 0;
}
Here are the isDelimiter() and isOperator() methods.
bool isOperator(char c)
{
if ((inputLine[c] == '+') || (inputLine[c] == '-') || (inputLine[c] == '*') || (inputLine[c] == '/') || (inputLine[c] == '=') || (inputLine[c] == '%') || (inputLine[c] == '<') || (inputLine[c] == '>'))
return true;
else
return false;
}
bool isDelimiter(char c)
{
if ((inputLine[c] == ';') || (inputLine[c] == '(') || (inputLine[c] == ')') || (inputLine[c] == ','))
return true;
else
return false;
}
Any help is appreciated!
EDIT::
After reviewing my code some more I realized the mistake, but I still have another. That runtime error was because in my isOperator() and isDelimiter() functions, I was checking inputString[c] rather than just 'c'. Silly mistake, I know. However, although there is no longer an error, the program still skips checking the isOperator() and isDelimiter() methods, and only goes into the else statement when it reads a ' '. Why isn't it going into my else statement for operators and delimiters?

Your functions take char, change them to int:
bool isDelimiter(char c) //should be int
{
if ((inputLine[c] == ';') || (inputLine[c] == '(') || (inputLine[c] == ')') || (inputLine[c] == ','))
return true;
else
return false;
}

I figured it out, and even though they're simple mistakes, maybe it'll help somebody in the future. After all, I was stumped for a while.
They were mainly just syntax errors, I really needed to freshen up on my coding.
This is the format my functions now follow. Notice I'm finally passing the correct values.
bool isDelimiter(char c)
{
if ((c == ';') || (c == '(') || (c == ')') || (c == ','))
return true;
else
return false;
}
And this is how I am now calling them. I was trying to check if the input itself was equal to the function, which would be like asking if "helloworld" == TRUE. Obviously that wasn't working, and I wanted to kick myself once I figured that out. Here's the snippet:
if ((inputLine[i] == ' ') || (isDelimiter(check)) || (isOperator(check)))
{
cout << lexer(inputString);
if (isDelimiter(check))
{
cout << inputLine[i] << "\t\tDELIMITER\n";
}
if (isOperator(check))
{
cout << inputLine[i] << "\t\tOPERATOR\n";
}
inputString = "";
} // end if
else
{
inputString = inputString + inputLine[i];
} // end else
That has resolved my basic issues, now onto bigger ones.

Related

Input Redirection - Cin not working with command line

I am tasked to write a simple program that reads in a file, and determines if the characters '(' '[' and '{' and "balanced". Meaning, There is a matching closing bracket/brace/parentheses for each opening one.
I am having trouble with the input. We are to use input redirection, not an iostream object, taking advantage of the command line. We utilize a makefile and when I run the executable it tells me 2 errors: not using argc and argv[].
struct Contents {
int numP;
int numS;
int numC;
};
int main(int argc, const char* argv[]) {
char word;
Contents c;
while(cin >> word) {
if(word == '{' || word == '}') {
c.numC++;
}
if(word == '(' || word == ')') {
c.numP++;
}
if(word == '[' || word == ']') {
c.numS++;
}
}
if(c.numC % 2 == 0 || c.numP % 2 == 0 || c.numS % 2 == 0) {
cout << "Balanced" << endl;
}
else {
cout << "Not Balanced" << endl;
}
return 0;
}
What am I missing here to make the file redirection input work? When I run this in XCode I just enter a bunch of values and it never ends. I can't seem to do the input right.
Thank you!
You need to break out of the while loop, if you are reading from a file then your code should work as it is. I have just made a small change to the logic when checking whether it is balanced or not.
int main() {
char word;
Contents c;
while (cin >> word) {
if (word == '{' || word == '}') {
c.numC++;
}
if (word == '(' || word == ')') {
c.numP++;
}
if (word == '[' || word == ']') {
c.numS++;
}
}
// Edited here: Check using and instead of or.
if (c.numC % 2 == 0 && c.numP % 2 == 0 && c.numS % 2 == 0) {
cout << "Balanced" << endl;
} else {
cout << "Not Balanced" << endl;
}
return 0;
}
Update:
I have tested the code, so here is the output.
Here is the output. You can redirect the input to any file and it will scan the file until it reaches EOF.

C++ white space string

I'm brand new into C++. I would like to know, why my code is not working.
I've got string called Response.
If the response begins with y/Y it should proceed. However I would like to proceed when the user types " y"/" Y" (the white space) as well.
Here is my code.
Thanks in advance!
bool AskToPlayAgain()
{
std::cout << "Would you like to play again? Yes/N";
std::string Response = "";
std::getline(std::cin, Response);
return (Response[0] == 'y') || (Response[0] == 'Y' +) ||(Response[0] == ' y' +) (Response[0] == ' Y' +);
std::cout << std::endl;
}
With Response[0] you access the first character of the string. You can compare that, as you do, with a character constant, such as 'y'. However, if you want to allow the leading space, this is no longer a single character, so your comparison Response[0] == ' y' cannot work.
Here is a version which allows as many space characters as needed, and then y or Y (C++11 version):
for (auto c:Response)
if (c!=' ')
return (c=='y') || (c=='Y');
//string is only spaces
return false;
You can traverse string Response and ignore white spaces(I am considering Tabs and Spaces in this case) while traversing.
If first character is non white space then you can break the loop I am using flag yes in this case.
bool AskToPlayAgain()
{
std::cout << "Would you like to play again? Yes/N";
auto Response="";
std::getline(std::cin, Response);
auto yes = false;
auto itr = Response.begin();
while(itr != Response.end())
{
if(*itr != ' ' && *itr !='\t')
{
yes = (*itr == 'y' || *itr =='Y') ;
break;
}
++itr;
}
return yes;
}
You can remove the spaces from the response and check with only 'Y'/'y'.
bool AskToPlayAgain()
{
std::cout << "Would you like to play again? Yes/N";
std::string Response = "";
std::getline(std::cin, Response);
Response.erase(remove(Response.begin(), Response.end(), ' '), Response.end());
return (Response[0] == 'y') || (Response[0] == 'Y');
}
Use a loop to check each of your character inside the input string...
For example, like this, usage of the usual loop which can be used in all versions of C++ (You can use the range based for loop like in the above answer...):
bool ask_to_play_again(std::string Response)
{
for (auto i = 0; i < Response.size(); i++)
if (!isspace(Response[i])) // Is not a whitespace character
return tolower(Response[i]) == 'y';
return false; // If the user enters invalid input, close the game anyway...
}
Kind regards,
Ruks.
Maybe you can use std::find function to resolve the problem.
bool AskToPlayAgain()
{
std::cout << "Would you like to play again? Yes/N";
std::string Response = "";
std::getline(std::cin, Response);
auto pos1 = Response.find("Y");
auto pos2 = Response.find("y");
if (pos1 != std::string::npos || pos2 != std::string::npos)
return true;
return false;
}

Efficient way for a while loop with string for entire alphabet (C++)

I'm very new to c++ and am working on getting the hang of functions. For this assignment, I'm programming a calculator.
My question revolves around this snip bit of code:
else
{
cout << "\nEnter a letter from the selection!";
}
If I do this and enter just any letter, the code will continue to the next function and ask the user to enter a number. Well, I figured a while loop would fix this, but I can't figure out any other way to do it besides listing the entire alphabet in my bool statement! Is there a more efficient way to do this? Here is my entire function for reference:
string mathCalcChoice(string letter)
{
string name;
if ((letter == "A") || (letter == "a"))
{
name = "add";
}
else if ((letter == "B") || (letter == "b"))
{
name = "subtract";
}
else if ((letter == "C") || (letter == "c"))
{
name = "divide";
}
else if ((letter == "D") || (letter == "d"))
{
name = "multiply";
}
else if ((letter == "E") || (letter == "e"))
{
name = "the power of";
}
else
{
cout << "\nEnter a letter from the selection!";
}
return name;
}

reassigning strings in a vector using loops

I am a beginner learning c++ trying to write a program that will read words into a vector, replace "bad" words with "BLEEP" and print out the vector after it is censored.
Here is where I think my mistakes might be...
nested loop - if in a while
words.size - should it be words.length?
Any insight is appreciated
#include "../../std_lib_facilities.h"
int main()
{
cout << "type in text";
vector<string> words;
string word = "";
while (cin >> word)
{
{
if (word == "boo" || "broccoli" || "moist")
word = "BLEEP";
}
words.push_back(word);
}
for (int i = 0; i < words.size(); ++i)
cout << "" << words[i] << "";
}
if (word == "boo" || "broccoli" || "moist")
is not the correct way to chain multiple conditions together. You need to recheck the condition in each part.
if (word == "boo" || word == "broccoli" || word == "moist")
When you have
if (word == "boo" || "broccoli" || "moist")
It is translated to
if (word == "boo" || true || true)
So it will always be true.

Delimiter matching simple program won't work

I have looked over this for hours it seems like. This program will compile, it just can't detect errors correctly. And for some reason it will work when I type in hey [) or hey {], etc. But it won't work for hey[) or hey{]. Obviously in all cases it should detect an error but for some reason the space after 'hey' makes a difference.
#include<iostream>
#include <stack>
using namespace std;
bool delimiterMatching(char *file){
stack<char> x;
int count = 0;
char ch, onTop, check;
while(ch != '\0'){
ch = file[count];
if (ch == '(' || ch == '[' || ch == '{')
x.push(ch);
else if (ch == ')' || ch == ']' || ch == '}') {
onTop == x.top();
x.pop();
if((ch==')' && onTop!='(') || (ch==']' && onTop!='[') || (ch=='}' &&
onTop!= '{'))
return false;
}
count++;
}
if (x.empty())
return true;
else
return false;
}
int main()
{
char *test = new char();
cout << "enter sentence: ";
cin >> test;
if (delimiterMatching(test))
cout << "success" << endl;
else
cout << "error" << endl;
return 1;
}
With cin >> test you don't get a whole sentence, but only a string until cin encounters whitespace. So if you type (hey ), thest would be (hey and the closing brace would only be read by the next >>, whereas (hey) would work as expected.
You have a second issue with your test allocation, which might be too short for reasonable input.
Change main() as follows:
char *test = new char[256]; // enough space. COnsider also string
cout << "enter sentence: ";
cin.getline(test, 256); // full line input.
...
You have also two nasty bugs in delimiterMatching().
First you use an uninitialized ch in your while condition. Either initialise ch to a non nul char, or use while (file[count]).
And did you notice onTop == x.top(); ? Shouldn't it be onTop = x.top();?