C++ string operations giving me weird/inconsistent/wrong results - c++

I am trying to read a sequence which is supposed to be in the form of:
variable operator variable operator variable. . . and so on, where the 'variable' consists is either A , B , or C and the 'operators' are one of the four basic operators + - / * , and simply print valid if it conforms to that given form and invalid if it doesn't. Also, the conditions are that the sequence must start with a single variable and be followed (spaces are allowed in between) by an operator.
I have already made up some code where I take the string input and just have a function called 'check' to see if it returns false, making the program print 'Invalid'. Here is my main function:
using namespace std;
int main() {
string m;
cout<<"Please enter a sequence: "<<endl;
getline(cin,m);
bool allow = check(m);
if(allow == true){
cout<<"\n\nCorrect format "<<endl;
}
else{
cout<<"\n\nIncorrect format \n"<<endl;
}
system("PAUSE");
return 0;
}
And here is my check function:
bool check(string mi){
int c=0; //using c as an index,
mi.append("0"); //append a 0 as a signal to when the string ends
while(c < mi.length()){
if(mi.at(c)=='0'){}
else if(isblank(mi.at(c))){} //So it will accept spaces between the input
else if(mi.at(c) == 'A' ||mi.at(c) == 'B' ||mi.at(c) == 'C'){
//The sequence must start with a variable...
c +=1; //increment to start at the next character...
while(c < mi.length()){ //This whole loop is to check if the next
//significant character is one of the operators
if(isblank(mi.at(c))){}
else if(mi.at(c) !='+' ||mi.at(c) != '-' ||mi.at(c) != '/' || mi.at(c) != '*' || mi.at(c) !='0'){
cout<<"\n(Log) Character at "<<c<<" was not an operator? Value: "<<mi.at(c);
//Why does it always come here even if the value was an operator?
return false;
}
c++;
}
}
c++;
}
return true; //Assume true if there are no errors...
}
Even if I input a correct sequence, say A+B+C , it still comes up as being invalid. I have traced the problem to the particular line of code above. Why does it do this?

Because your boolean logic is incorrect.
The expression:
mi.at(c) !='+' || mi.at(c) != '-' || mi.at(c) != '/' || mi.at(c) != '*' || mi.at(c) !='0'
will evaluate as true every time. For example, if mi.at(c) is a '-', then mi.at(c) != '+' evaluates to true and your into that part of the code you don't want to be in. Likewise, if i.at(c) is a '+' then mi.at(c) != '-' evaluates true and again your conditional evaluates as true again.
I believe you want to change your boolean or's (||) to boolean and's (&&).
For some unsolicited advice, personally I would suggest taking a moment to think of the problem as a state machine. This will enable you to clean up and think about what it is doing in a supportable and expandable fashion. I'm not a c++ coder, but here is how I would approach it in c as a state machine. You should be able to translate it to c++:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
main() {
char* VARS = "ABC";
char* OPS = "+-/*";
char c = EOF;
int state = 0;
while (((c = getchar()) != EOF) && (state < 3)) {
// move on to next character if we have a blank or end-of-line
if (c == ' ' || c == '\n')
continue;
// test to see if the character is a var or op
int isvars = (strchr(VARS, c) != NULL);
int isops = (strchr(OPS, c) != NULL);
// based upon character type and current state, determine next state
if (!isvars && !isops) // character is neither a valid var nor op
state = 3;
else if (isvars) // character is a var
if ((state == 0) || (state == 2))
state = 1;
else if (state == 1)
state = 3;
else if (isops) // character is an op
if ((state == 0) || (state == 2))
state = 3;
else if (state == 1)
state = 2;
}
puts((state > 1) ? "bad" : "good");
}
And, here is the result after compiling it to 'varop':
$ echo "" | ./varop
good
$ echo "A" | ./varop
good
$ echo "+" | ./varop
bad
$ echo "A+" | ./varop
bad
$ echo "AA" | ./varop
bad
$ echo "A+" | ./varop
bad
$ echo "A+A" | ./varop
good
$ echo "A++" | ./varop
bad
$ echo "A + B" | ./varop
good
$ echo " A + B" | ./varop
good
$ echo "D" | ./varop
bad
$ echo "%" | ./varop
bad

You are correct in where your problem is, however problem is your basic logic. Because you use || and not &&, that means that your statement will always evaluate to true (i.e. '+' will evaluate to false in the first condition, but will evaluate to true when checking for not -). What you need to do is replace the || operators in the culprit line with && and your check function should behave as expected.
Also, as a style note, on line 8 of your check function, instead of c += 1, you should use c++ for the sake of consistancy.

Try this out, it compiles and gives the desired output. However it still not enforcing that an operator should be followed by a character for example. But i guess you can figure that out.
using namespace std;
To help, i made an array of possible operators along with a function that checks if a character is an operator or not.
unsigned char operators[] = { '+','-','/','*' };
bool isOperator(const unsigned char &m) {
for (int n = 0; n < 4; n++) if (m == operators[n]) return true;
return false;
}
In your check there is only one loop needed and a for loop is much more conveniant. Notice the logic, i continue when the character is a A or B or C or when it is blank.
bool check(string mi){
for (int c = 0; c < mi.size(); c++) {
cout << mi.at(c);
if (isblank(mi.at(c))) continue;
if (mi.at(c) == 'A' || mi.at(c) == 'B' || mi.at(c) == 'C') continue;
if (!isOperator(mi.at(c))) {
cout<<"\n(Log) Character at " << c <<" was not an operator? Value: "<<mi.at(c);
return false;
}
}
return true; //Assume true if there are no errors...
}
int main() {
string m;
cout<<"Please enter a sequence: "<<endl;
getline(cin,m);
cout << "\n\n" << string(check(m) ? "Correct":"Incorrect") << " format." << endl;
system("PAUSE");
return 0;
}
Output:
Please enter a sequence:
A+B+C
A+B+C
Correct format.
Press any key to continue . . .

I would suggest using std::istringstream and using std::copy to get the separate components into a std::vector of characters. Then it's simple to iterate over the vector to check for only the valid components.
To help with getting the components into the vector with std::copy, I suggest you read about std::istream_iterator and std::back_inserter.

Related

how do I save string without some of its characters?

I'm writing a programm which gives out the input string without its vowels.but it only gives the first charachter of the string .here is the code:
#include<iostream>
using namespace std;
int main(){
char ch;
while(cin.get(ch)){
cout<<ch;
char a=cin.peek();
while( a==65 || a==69 || a==73 || a==79 || a==85 || a==97 || a==101 || a==105 || a==111 || a==117)
cin.ignore(1 , a);
}
return 0;
}
To solve a problem like this, start by breaking the problem into smaller parts. A possible decomposition is:
Are there characters still to read from the input? No: Great, we are done!
Read in a character
Is the character a vowel? Yes: Goto 1.
Output the character
Goto 1.
Then in code, you can translate this into:
// 1) Are there characters still to read?
while (std::cin.good())
{
// 2) Read in a character
char ch;
std::cin.get(ch);
// 3) Is the character a vowel?
// For the test for a vowel, you can use something similar to
// what you have at the moment, or better still: consider
// writing a function like isVowel in #Shreevardhan answer.
if ( /* TODO: Test if the character is a vowel... */)
{
// Skip the rest of the loop and go back to 1
continue;
}
// 4) Output the good character
std::cout << ch;
// 5) Reached the end of the loop, so goto 1
}
It's a good habit to break your problem down into smaller parts. I often start a new project by first writing out a list/comments (or even drawing a flow diagram) to break up the problem into more manageable pieces.
Other answers show how to solve this problem in a more intuitive manner.
Anyway, when looking at your code consider the following:
while( a==65 || a==69 || a==73 || a==79 || a==85 || a==97 || a==101 || a==105 || a==111 || a==117)
cin.ignore(1 , a);
As you do a while loop with conditions around the value of a, and as cin.ignore(1 , a) does not change the value of a, you wont ever leave this loop unless an exception is thrown, right?
Maybe you can try to use the boost library.
#include <boost/algorithm/string.hpp>
boost::erase_all(str, "a");
Something like this
#include <iostream>
using namespace std;
bool isVowel(char c) {
c = tolower(c);
return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
}
int main() {
char c;
while (cin.get(c))
if (!isVowel(c))
cout << c;
return 0;
}
Add your storing logic inside.
A more C++-ish code
#include <algorithm>
#include <iostream>
using namespace std;
int main() {
string s;
getline(cin, s);
s.erase(remove_if(s.begin(), s.end(), [](char c) {
c = tolower(c);
return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
}), s.end());
cout << s;
return 0;
}
See a demo.

Pig Latin Program

I'm not getting errors, but the output is incorrect. I'm not sure what I'm doing wrong. I can only use functions from string library.
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
int main() {
string message, pig_message;
getline(cin, message);
unsigned int x = message.find_first_of("aeiou");
if (message[x] == 'a' || 'e' || 'i' || 'o' || 'u' ) {
pig_message = message + "yay";
cout << pig_message;
}
else if (!(message[x] == 'a' || 'e' || 'i' || 'o' || 'u' )) {
pig_message = message.substr(1) + message[0] + "ay";
cout << pig_message;
}
system("pause");
return 0;
}
The first if statement is always true. You should change it to
if (message[x] == 'a' || message[x] == 'e' || message[x] == 'i' || message[x] == 'o' || message[x] == 'u' ) {
Also, you could change the else if (...) { line to just
else {
if you want it to be executed every time the first if statement is not true.
Your comparison statement is incorrect.
Make sure your function is actually iterating through the letters, and that you're concatenating the strings correctly.
So:
unsigned int x = message.find_first_of("aeiou"); // Returns the first match
if(message[x] == 'a' || message[x] == 'e'...) // Currently your code reads as only checking for a.
Think of it as IF message[x] = a, IF e, IF i
vs
if message[x] = a, IF message[x] = i
What does your code do after it finds a match?
pig_message = message + 'yay' would add "yay" to the whole message string.
It would then print it out and move on, without doing anything to the other vowels.
I'm new to C++ myself but that's how I've understood your code.
It might be better to go through the whole input string one letter at a time in a for loop with your if else statements to add the strings inside the loop.

Reverse string using recursion without specific seperators

I have an assignment which requires "Recursively reads one character at a time from the text file until a separator is encountered" -
Those non-separator characters are then displayed in reverse order, with the last character displayed being capitalized
Let's say file has below line and separator is !, white space and so on.
abc! ndtv
Expected output is:
Cba! Vtdn
I have written below code and I am getting the expected output — but one condition is I am supposed to do it using only two variables, and I am not able to do it with less than 3. Any pointers how to achieve it with 2 variables only?
int Reverse(ifstream &inFile, int level)
{
int myInput;
static int returnValue;
static int levelofinterest;
myInput = inFile.get();
if (!(isspace(myInput) || ((char)myInput == '.') ||
((char)myInput == '!') || ((char)myInput == ',') ||
((char)myInput == '?') || ((char)myInput == ';') ||
((char)myInput == ':') || ((char)myInput == '\0')||
myInput == EOF))
{
level++;
Reverse(inFile,level);
}
else
{
levelofinterest = level;
returnValue = myInput;
}
if(!(isspace(myInput) || ((char)myInput == '.') ||
((char)myInput == '!') || ((char)myInput == ',') ||
((char)myInput == '?') || ((char)myInput == ';') ||
((char)myInput == ':') || ((char)myInput == '\0')||
myInput == EOF))
{
level--;
if ((levelofinterest - 1) == level)
{
cout << (char)toupper(myInput);
}
else
{
cout.put((char)myInput);
}
}
return returnValue;
}
This code almost meets your requirements (but I'm not completely happy with it). It has only one extra variable over and above the arguments to the function. However, I altered the function signature — the code doesn't use the return value, so the function is defined as returning void. It probably can be modified to meet your alternative calling convention and the loop structure outlined in your (transcribed) comments.
#include <iostream>
#include <cctype>
using namespace std;
static void Reverse(istream &inFile, int level)
{
int c = inFile.get();
if (c == EOF)
return;
if (isalpha(c))
{
Reverse(inFile, level + 1);
if (level == 0)
cout << (char)toupper(c);
else
cout << (char)c;
}
else if (level > 0)
inFile.unget();
else
cout << (char)c;
}
int main()
{
while (cin)
Reverse(cin, 0);
return 0;
}
I call the source code recrevstr.cpp and compiled the program (using make) with the command:
g++ -O3 -g -std=c++11 -Wall -Wextra -Werror recrevstr.cpp -o recrevstr
and then run it:
$ ./recrevstr <<< 'abc! ndtv'
cbA! vtdN
$
It takes various short cuts. In particular, all non-alphabetic characters are delimiters. It uses an istream rather than an ifstream, and the main() is configured so standard input (aka cin) is processed. Like your sample code, it relies on a loop in the calling code to make sure the job is complete. I start with level 0; it's trivial to start with level 1 instead.
Note that any code using cout with << operators to produce output is inherently C++ and not directly applicable to C. This effect can be neutralized by using <cstdio> and FILE * (and stdin), plus appropriate I/O functions, which could then make it bilingual, though there'd need to be conditional compilation to get the std namespace out of the way.

Evaluating a single char in an if statement: C++

I am having some troubles with my if loop.
First off I have I assigned char sign.
void evaluate_ps(istream& input)
{
char sign;
input >> sign;
cout << sign << endl;
check(sign);
}
That prints / so my sign has the value '/'
Then I go to my void check(char operation) function
void check(char operation)
{
if(operation != '-' || operation != '+' ||
operation != '*' || operation != '/')
{
return false;
}
else return true;
}
and it's returning false... WHY!!!! I can't seem to figure this out.
Thanks everyone.
This happens because you are using the || (OR) operator. When operation is / the check operation != '-' returns true. Since || is short circuited, the entire expression returns true.
Change it to && (AND):
if (operation != '-' && operation != '+' &&
operation != '*' && operation != '/')
Another way to write this is:
if (!(operation == '-' || operation == '+' ||
operation == '*' || operation == '/'))
You probably meant all your || to be &&:
if(operation != '-' && operation != '+' &&
operation != '*' && operation != '/')
Otherwise, it will always enter the if-statement since a character will always not equal one of 4 different things.
The if statement is responding to the / not equaling one of the other values
Think about "or" even in a general sense
if blue is not green or is not red or is not blue say nope
you would need to do something like the following:
if (operation != '+' && operation != '-' && operation != '/' && operation != '*') {
return false;
}
return true;
this way its like this
if blue is not green and is not red and is not blue say nope

Why the if statement does not work with multiple conditions in C++? [duplicate]

This question already has answers here:
Why does non-equality check of one variable against many values always return true?
(3 answers)
Closed 10 months ago.
I have run into a strange to me problem. For some reason multiple || statements, even divided by commas and parenthesis will not work. The last thing I expected to work is the & statement, which requires for both conditions to be met, but in my case it works for one condition as if it was an OR statement.
Someone please explain to me why is this happening. I am very confused.
WORKS:
#include<iostream>
#include<vector>
#include<string>
using namespace std;
int main()
{
string quest;
quest = "Where is my dog?";
string::iterator m;
vector<string>question;
string t;
for(m = quest.begin(); m != quest.end(); m++)
{
if(*m != ' ' & *m != ',' & *m != '?' & *m != '.') //works with & and &&
{
t.push_back(*m);
}
else
{
cout << t << endl;
question.push_back(t);
t.clear();
}
}
}
Does not work:
#include<iostream>
#include<vector>
#include<string>
using namespace std;
int main()
{
string quest;
quest = "Where is my dog?";
string::iterator m;
vector<string>question;
string t;
for(m = quest.begin(); m != quest.end(); m++)
{
if(*m != ' ' || *m != ',' || *m != '?' || *m != '.') // DOES NOT WORK
{
t.push_back(*m);
}
else
{
cout << t << endl;
question.push_back(t);
t.clear();
}
}
}
if(*m != ' ' || *m != ',' || *m != '?' || *m != '.') // DOES NOT WORK
What would you expect that to do? You're asking whether something is not A or not B. Either one of those is always true (as long as A and B are not the same thing), so your expression as a whole is always true.
It looks like you might want:
if(*m != ' ' && *m != ',' && *m != '?' && *m != '.')
That condition will be true if *m is anything other than space, comma, question mark, or period.
You should use && for logical "and".
& operator is for bitwise "and", which in your case produces true since all the characters in the statement have at least one common bit lit.
What is it that you're trying to do?
Note, that if the intention is to filter out " ,?." characters, then the right thing to do is to use && because || will not do that (because each character will fit at least one, so you will never get into the else clause, always go to then).
Or looks at the first if it doesn't match it goes onto the next one and checks it else it executes the code. So if m is ' ' it'll fail the first test, but the second test will pass as ' ' is not ','.
I expect what you actually want is something along the lines of:
if (!(*m == ' ' || *m == ',' || *m == '?' || *m == '.'))
You should be using && over & as && is a logical operator where & is a bitwise operator.
When it comes to if tests, you need to remember how the operators work.
Using logical OR (||) means that if one of the conditions is true then the whole statement is true.
Using logical AND (&&) means that if all of the conditions are true then the whole statement is true.
See this page for help on C++ operators. About half-way down is the section on Logical and Bitwise operations.
Edit: Hopefully this code example will help clear up your confusion:
int A = 0;
int B = 1;
if (A == 0 && B == 0) {
//This code will not run, as the whole statement is false
. . . .
}
if (A == 0 && B == 1) {
//This code will run, as the whole statement is true
. . . .
}
if (A == 0 || B == 0) {
//This code will run, as A = 0, so the whole statement is true
. . . .
}