While loop continuing after break condition met - c++

My current assignment requires me to allow for a user to pass strings of characters and convert from roman numerals to a decimal value. I've faced an issue that when random words are passed through the program it must return the longest valid prefix and ignore the remaining characters. My code runs through a while loop and once it reaches the break condition it repeats the code again for the remaining characters. I'm unsure what next step I should take to fix this code to output correctly. Following image shows the characters to pass through the code.
Image of test failure
#include <iostream>
#include <ctype.h>
using namespace std;
int
main (){
while (!cin.eof ()){
char inputChar;
int result = 0;
while (cin.get (inputChar))
{
inputChar = toupper (inputChar);
if (inputChar == 'M')
result = result + 1000;
else if (inputChar == 'D')
{
inputChar = cin.peek ();
inputChar = toupper (inputChar);
if (inputChar == 'M')
{
result = result - 500;
continue;
}
else if (inputChar == 'D'){
result = result;
continue;
}
else
{
result = result + 500;
continue;
}
}
else if (inputChar == 'C')
{
inputChar = cin.peek ();
inputChar = toupper (inputChar);
if (inputChar == 'M' || inputChar == 'D')
{
result = result - 100;
continue;
}
else
{
result = result + 100;
continue;
}
}
else if (inputChar == 'L')
{
inputChar = cin.peek ();
inputChar = toupper (inputChar);
if (inputChar == 'M' || inputChar == 'D' || inputChar == 'C')
{
result = result - 50;
continue;
}
else
{
result = result + 50;
continue;
}
}
else if (inputChar == 'X')
{
inputChar = cin.peek ();
inputChar = toupper (inputChar);
if (inputChar == 'M' || inputChar == 'D' || inputChar == 'C'
|| inputChar == 'L')
{
result = result - 10;
continue;
}
else
{
result = result + 10;
continue;
}
}
else if (inputChar == 'V')
{
inputChar = cin.peek ();
inputChar = toupper (inputChar);
if (inputChar == 'M' || inputChar == 'D' || inputChar == 'C'
|| inputChar == 'L' || inputChar == 'X')
{
result = result - 5;
continue;
}
else
{
result = result + 5;
continue;
}
}
else if (inputChar == 'I')
{
inputChar = cin.peek ();
inputChar = toupper (inputChar);
if (inputChar == 'M' || inputChar == 'D' || inputChar == 'C'
|| inputChar == 'L' || inputChar == 'X' || inputChar == 'V')
{
result = result - 1;
continue;
}
else
{
result = result + 1;
continue;
}
}
else{
break;
}
}
if (result != 0)
{
cout << result << endl;
}
}
return 0;
}

Your break statement does not go out of the both while loops. It only breaks the inner loop, not the outer one. You can use a flag to tell the outer loop not to continue:
int main()
{
bool exit_loop = false; // define a flag here
while (!cin.eof()) {
char inputChar;
int result = 0;
if (exit_loop) // check the flag here
break;
while (cin.get(inputChar))
{
and while breaking set the flat to true:
}
else
{
exit_loop = true; // set the flag here
break;
}

Maybe try clearing the buffer at the end of the outer loop. This way the longest prefix is printed and the same word isn't being used again through the iteration.
if (result != 0)
{
cout << result << endl;
}
cin. ignore(10000, '\n'); //used to ignore or clear characters from the input buffer
}

Related

iterate char by char through vector of strings

I want to iterate char by char in a vector of strings. In my code I created a nested loop to iterate over the string, but somehow I get an out of range vector.
void splitVowFromCons(std::vector<std::string>& userData, std::vector<std::string>& allCons, std::vector<std::string>& allVows){
for ( int q = 0; q < userData.size(); q++){
std::string userDataCheck = userData.at(q);
for ( int r = 0; r < userDataCheck.size(); r++){
if ((userDataCheck.at(r) == 'a') || (userDataCheck.at(r) == 'A') || (userDataCheck.at(r) == 'e') || (userDataCheck.at(r) == 'E') || (userDataCheck.at(r) == 'i') || (userDataCheck.at(r) == 'I') || (userDataCheck.at(r) == 'o') || (userDataCheck.at(r) == 'O') || (userDataCheck.at(r) == 'u') || (userDataCheck.at(r) == 'U')){
allVows.push_back(userData.at(r));
}
else if ((userDataCheck.at(r) >= 'A' && userDataCheck.at(r) <= 'Z') || (userDataCheck.at(r) >= 'a' && userDataCheck.at(r) <= 'z')){
allCons.push_back(userData.at(r));
}
else {
continue;;
}
}
}
}
The error here is in these lines:
allVows.push_back(userData.at(r));
allCons.push_back(userData.at(r));
the r variable is your index into the current string, but here you're using it to index into the vector, which looks like a typo to me. You can make this less error prone using range-for loops:
for (const std::string& str : userData) {
for (char c : str) {
if (c == 'a' || c == 'A' || ...) {
allVows.push_back(c);
}
else if (...) {
....
}
}
}
which I hope you'll agree also has the benefit of being more readable due to less noise. You can further simplify your checks with a few standard library functions:
for (const std::string& str : userData) {
for (char c : str) {
if (!std::isalpha(c)) continue; // skip non-alphabetical
char cap = std::toupper(c); // capitalise the char
if (cap == 'A' || cap == 'E' || cap == 'I' || cap == 'O' || cap == 'U') {
allVows.push_back(c);
}
else {
allCons.push_back(c);
}
}
}
Since this question is about debugging actually, I think it is a nice illustration of how the usage of std::algorithms of C++ can decrease the effort needed to see what is wrong with a non working code.
Here is how it can be restructured:
bool isVowel(char letter)
{
return letter == 'A' || letter == 'a' ||
letter == 'E' || letter == 'e'||
letter == 'O' || letter == 'o'||
letter == 'Y' || letter == 'y'||
letter == 'U' || letter == 'u';
}
bool isConsonant(char letter)
{
return std::isalpha(letter) && !isVowel(letter);
}
void categorizeLetters(const std::vector<std::string> &words, std::vector<char> &vowels, std::vector<char> &consonants)
{
for( const std::string &word : words){
std::copy_if(word.begin(), word.end(), std::back_inserter(vowels), isVowel);
std::copy_if(word.begin(), word.end(), std::back_inserter(consonants), isConsonant);
}
}
With a solution like this, you avoid the error-prone access-with-index that lead to your problem. Also, code is readable and comprehensive

String and character comparison

I am new to programming and I need to search any string to see if it includes only the letters a,b,c,d,e or f. The minute the program finds a letter that is not one of those the program should return false. Here is my function
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if ((word[index] == 'a') || (word[index] == 'b') || (word[index] == 'c')||
(word[index] == 'd')|| (word[index] == 'e')|| (word[index] == 'f')) {
return true;
}
else {
return false;
}
index++;
}
}
Thank you very much for nay help! :)
The moment the return statement is encountered, the function is exited. This means that the moment any of the characters 'a', 'b', 'c', 'd', 'e', 'f' is encountered while iterating, due to the return statement the function will be exited immediately.
You can use std::string::find_first_not_of as shown below:
std::string input = "somearbitrarystring";
std::string validChars = "abcdef";
std::size_t found = input.find_first_not_of(validChars);
if(found != std::string::npos)
std::cout << "Found nonfavorite character " <<input[found]<<" at position "<<found<< std::endl;
else
{
std::cout<<"Only favorite characters found"<<std::endl;
}
If you unroll the loop by hand, you will spot the problem immediately:
if ((word[0] == 'a') || (word[0] == 'b') || (word[0] == 'c')||
(word[0] == 'd')|| (word[0] == 'e')|| (word[0] == 'f')) {
return true;
}
else {
return false;
}
if ((word[1] == 'a') || (word[1] == 'b') || (word[1] == 'c')||
(word[1] == 'd')|| (word[1] == 'e')|| (word[1] == 'f')) {
return true;
}
else {
return false;
}
//...
That is, the return value depends only on the first element.
"The minute the program finds a letter that is not one of those the program should return false" means
if ((word[0] != 'a') || (word[0] != 'b') || (word[0] != 'c')||
(word[0] != 'd')|| (word[0] != 'e')|| (word[0] != 'f')) {
return false;
}
if ((word[1] != 'a') || (word[1] != 'b') || (word[1] != 'c')||
(word[1] != 'd')|| (word[1] != 'e')|| (word[1] != 'f')) {
return false;
}
// ...
// After checking all the characters, you know what all them were in
// your desired set, so you can return unconditionally.
return true;
or, with a loop:
while (index < length) {
if ((word[index] != 'a') || (word[index] != 'b') || (word[index] != 'c')||
(word[index] != 'd')|| (word[index] != 'e')|| (word[index] != 'f')) {
return false;
}
index++;
}
return true;
bool is_favorite(string word){
return ( word.find_first_not_of( "abcdef" ) == std::string::npos );
}
It returns true if, and only if, there are only the characters 'a' through 'f' in the string. Any other character ends the search immediately.
And if you exchange string word with const string & word, your function will not have to create a copy of each word you pass to it, but work on a read-only reference to it, improving efficiency.
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if (word[index] > 'f' || word[index] < 'a')
return false;
index++;
}
return true;
}
The return true is logically in the wrong place in your code.
Your version returns true as soon as it finds one letter that is a through f. It's premature to conclude that the whole string is valid at that point, because there may yet be an invalid character later in the string.
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if ((word[index] == 'a') || (word[index] == 'b') || (word[index] == 'c')||
(word[index] == 'd')|| (word[index] == 'e')|| (word[index] == 'f')) {
return true; // This is premature.
}
else {
return false;
}
index++;
}
}
Minimal change that illustrates where the return true should be: after the loop. The return true is reached only if and only if we did not detect any invalid characters in the loop.
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if ((word[index] == 'a') || (word[index] == 'b') || (word[index] == 'c')||
(word[index] == 'd')|| (word[index] == 'e')|| (word[index] == 'f')) {
// Do nothing here
}
else {
return false;
}
index++;
}
return true;
}
Obviously now that the affirmative block of the if is empty, you could refactor a little and only check for the negative condition. The logic of it should read closely to the way you described the problem in words:
"The minute the program finds a letter that is not one of those the program should return false."
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if (!is_letter_a_through_f((word[index])
return false;
index++;
}
return true;
}
I replaced your large logical check against many characters with a function in the above code to make it more readable. I trust you do that without difficulty. My own preference is to keep statements short so that they are readable, and so that when you read the code, you can hold in your short-term memory the logic of what you are saying about control flow without being overloaded by the mechanics of your letter comparison.

How can I evaluate a QChar object in a switch?

Going through a bunch of code, looking to improve it.
I came across this bit:
if (c == '<' || c == '>') {
pattern.append("\\b");
} else if (c == 'a') {
pattern.append("[a-zA-Z]");
} else if (c == 'A') {
pattern.append("[^a-zA-Z]");
} else if (c == 'h') {
pattern.append("[A-Za-z_]");
} else if (c == 'H') {
pattern.append("[^A-Za-z_]");
} else if (c == 'c' || c == 'C') {
ignorecase = (c == 'c');
} else if (c == 'l') {
pattern.append("[a-z]");
} else if (c == 'L') {
pattern.append("[^a-z]");
} else if (c == 'o') {
pattern.append("[0-7]");
} else if (c == 'O') {
pattern.append("[^0-7]");
} else if (c == 'u') {
pattern.append("[A-Z]");
} else if (c == 'U') {
pattern.append("[^A-Z]");
} else if (c == 'x') {
pattern.append("[0-9A-Fa-f]");
} else if (c == 'X') {
pattern.append("[^0-9A-Fa-f]");
} else if (c == '=') {
pattern.append("?");
} else {
pattern.append('\\');
pattern.append(c);
}
If c was a char, this would be easy to turn into a switch. c is a QChar;
How should I turn QChar into an interger and reliably compare it to the various cases >, = etc?
A QChar is a wrapper for a 16-bit UTF-16 character.
You can retrieve the value using QChar::unicode() that returns an unsigned short.
You can the write your switch like this:
QChar c;
switch (c.unicode()) {
case u'a':
...
}
Be careful with your case statements as if you use 8-bit char literals, it might not work as expected.
For instance é might be 0xE9 (Latin-1, UTF16), or 0x82 (CP437) or even 0xC3 0xA9 (UTF-8, which will not compile as it needs 2 characters).
The solution is to use UTF-16 literals that are part of C++ since C++11.
For exampleu'é' will always be compiled as a char16_t (~unsigned short) of value 0x00E9.
you can define something like a dictionary, and I mean a Map:
int main(int argc, char* argv[])
{
QMap<QChar, QString> myMap{{'a', "[a-zA-Z]"},{'X', "[^0-9A-Fa-f]"}, {'h', "[A-Za-z_]"}};
QString regex{};
regex.append(myMap.value('a', ""));
regex.append(myMap.value('5', ""));
regex.append(myMap.value('X', ""));
qDebug() << "myRegex: " << regex;
return 0;

Debug Assertion Failed in for

I got an error on second if
Making the exactly same if outside of for seems to work just fine, it returns the value from priority function, but when I try to do it in for it said that I'm trying to pass an invalid parameter to a function which considers it to be fatal.
#include <iostream>
#include <stack>
#include <string>
using namespace std;
int priority(char c);
int main()
{
stack<char>Operator;
string input;
string output;
getline(cin, input);
for (int i = 0; i < input.size(); i++)
{
if (input[i] == '(' || input[i] == ')' || input[i] == '+' || input[i] == '-' || input[i] == '*' || input[i] == '/')
Operator.push(input[i]);
else
output.push_back(input[i]);
if (priority(Operator.top()) == 3)
{
int aux = Operator.top();
Operator.pop();
while (priority(Operator.top() == 4))
{
output.push_back((char)Operator.top());
Operator.pop();
}
Operator.push(aux);
}
if (priority(Operator.top() == 2))
{
Operator.pop();
while (priority(Operator.top()) != 1)
{
output.push_back(Operator.top());
Operator.pop();
}
Operator.pop();
}
}
cout << output;
cin.ignore();
cin.get();
return 0;
}
int priority(char c)
{
if (c == '(')
return 1;
if (c == ')')
return 2;
if (c == '+' || c == '-')
return 3;
if (c == '*' || c == '/')
return 4;
}
The statement Operator.top() is being called on every symbol in the input string. That would probably work in case your string starts with a '(' symbol or with a unary plus, but what would happen in case of "2*2"?
As a perfect solution you should redesign your code to make it a finit automaton. As a simple ad hoc fix you should check if the current symbol is an operation or digit and don't call the Operator.top() in the latter case:
if (isdigit(input[i])) {
output.push_back(input[i]);
}
else {
Operator.push(input[i]);
if (priority(Operator.top()) == 3) {
// ...
}
// ...
}

For if statement, although it is true, it loops again

#include <stdio.h>
void clearKeyboard(void){
while(getchar()!='\n');
}
void pause(void){
printf("Press <ENTER> to continue...");
clearKeyboard();
}
int getMenuChoice(void){
int choice;
printf("1- List all items\n");
printf("2- Search by SKU\n");
printf("0- Exit program\n> ");
scanf("%d", &choice);
return choice;
}
int getYesOrNo(void){
char ch;
int ret;
ch = 0;
ret = 0;
while(ch != 'Y' || ch != 'y' || ch != 'N' || ch != 'n')
{
scanf("%c", &ch);
clearKeyboard();
if (ch == 'Y' || ch == 'y'){
ret = 1;
return ret;
}
if (ch == 'N' || ch == 'n'){
ret = 0;
return ret;
}
else if (ch != 'Y' || ch != 'y' || ch != 'N' || ch != 'n'){
printf("Only (Y)es or (N)o are acceptable: ");
}
}
return ret;
}
int main(void){
int choice;
int temp = 0;
choice = 0;
printf("=== TEST MENU ===\n");
pause();
while(temp == 0){
choice = getMenuChoice();
if (choice != 0){
printf("*** not implemented ***\n");
}
else{
printf("Do you really want to quit? ");
temp = getYesOrNo();
}
}
printf("=== END OF MENU TEST ===\n");
return 0;
}
When the code runs, it should print out the test menu
and I would have to press enter to continue
Then, it would display multiples of print statements(listall..search by...exit)
So, if the user types 0 in, it asks Do you really want to quit and if the user types y, it should quit
However, the problem is the program asks the user unnecessary question "Only (Y)es or (N)o are acceptable" one more time after it asks "Do you really want to quit?" when I already have typed y in which is valid answer.
Why is that?
p.s library is there existing
Scanf ("%d", &choice); consumes only the numeral character ( also crashes on any other input, iirc) but not the \r \l or \n characters, which will be consumed during the getYesOrNo function, if I am correct (somebody please correct me). That's why the program should display the (y)es/(n)o reminder directly after asking you whether you'd really want to quit.
That is also the reason why adding the clearKeyboard function makes it work as intended.
There are some other issues with that code (e.g. the UB mentioned in a comment). However, this
if (ch == 'Y' || ch == 'y'){
ret = 1;
return ret;
}
if (ch == 'N' || ch == 'n'){
ret = 0;
return ret;
}
else if (ch != 'Y' || ch != 'y' || ch != 'N' || ch != 'n'){
printf("Only (Y)es or (N)o are acceptable: ");
}
Is probably not what you want. The first if is independent of the if - else that comes afterwards, thus even if the first condition is true, the block after that will be evaluated. Most likely you want this instead:
if (ch == 'Y' || ch == 'y'){
ret = 1;
return ret;
}
else if (ch == 'N' || ch == 'n'){
ret = 0;
return ret;
}
else {
printf("Only (Y)es or (N)o are acceptable: ");
}
The condition ch != 'Y' || ch != 'y' || ch != 'N' || ch != 'n' wasnt really meaningful, as the character is always either not Y or not N, thus it was always true.
You should add a whitespace before %c to automatically skip any leading whitespaces.In your case '\n' is always stored into ch which is why else if (ch != 'Y' || ch != 'y' || ch != 'N' || ch != 'n') is always true
scanf(" %c", &ch); //This is the modified statement