Compare strings using == - c++

Code, as shown below, can be complied.
Problem: It always says "Invalid Employee id" even when I enter the correct employee id.
Please tell me why and how to do this correctly.
#include <iostream>
#include <iomanip>
using namespace std;
char select, js;
char empid[4];
double bSalary, bonus, tot=0.0;
int main()
{
do
{
cout<<"Employee id: ";
cin>>empid;
if(empid=="M001" || empid=="A004" || empid == "M002") //these are employee ids
{
cout<<"Job Status: ";
cin>>js;
if(js=='P' || js=='C')
{
cout<<"Basic Salary: ";
cin>>bSalary;
if(bSalary>75000 && js=='P')
{
bonus = bSalary*(20.0/100.0);
tot = tot + bonus + bSalary;
}
else if(bSalary>75000 && js=='C')
{
bonus = bSalary*(15.0/100.0);
tot = tot + bonus + bSalary;
}
else
tot = tot+bonus+bSalary;
}
else
cout<<"Invalid Job Status"<<endl;
}
else
cout<<"Invalid Employee no"<<endl;
cout<<"Do you want to continue: ";
cin>>select;
cout<<endl;
}while(select=='y'||select=='Y');
cout<<"Total cost: "<<setprecision(2)<<setiosflags(ios::fixed)<<tot<<endl;
return 0;
}
Note: It is going to the else clause all the time.

It's this:
char empid[4];
This is too small as there's no room for a NUL terminator after the id. You could just change it to 5, but then if someone deliberately or accidentally typed a longer string your program may crash (it's called a buffer overrun, and in some situations can allow whoever provides input to hack the account running the program).
Further, == doesn't work for character arrays: you have to use e.g.:
if (strcmp(empid, "M001") == 0 || strcmp(empid, "A004") == 0 || ...
You would be much better off using a std::string, which will grow to accommodate the actual input (including a NUL terminator though that's not counted in a string's .size()), and works intuitively with ==.
Separately, your...
tot = tot+bonus+bSalary;
...is broken, as bonus may be uninitialised you mustn't read from it in an expression. You can simply remove bonus from the addition above, if it's meant to be 0 for the relevant employees.

You can't compare C strings with == or !=. As you can see that empid here is just a pointer so == will compare the base addresses of those strings not the strings themselves.
You need to use strcmp and include
#include <cstring>
.
.
.
if(strcmp(empid,"M001")==0 || ...)

Empid is not a string. C++ doesn't have a built-in == overload to compare char arrays.
You can make your own == operator. But don't bother. Declare empid as a string and watch magic happen.
string empid;

Changing the size of the char array to take care of NULL char will not work here.
char empid[5]
"==" operator do not work properly with char arrays. please change the condition to below:
if (0 == (strcmp(empid, "M001")) || (0 == (strcmp(empid, "A004"))) || (0 ==
(strcmp(empid, "M002"))))
EDIT:people above has already answered your question. My answer is redundant now.

Related

C++: Not recognizing char value when evaluating if statement

Every time I run this code, for whatever reason, it calls all functions regardless of whether the if statement evaluates to true
int main()
{
char StartUnit, EndUnit;
double StartVal = 0, EndVal = 0;
double CalcVal = 0;
static double result = 0;
//Receive user input
cout << "Please enter the unit which you would like to convert from: ";
cin >> StartUnit;
cout << "What is your initial value?: ";
cin >> StartVal;
cout << "Please enter the unit which you would like to convert to: ";
cin >> EndUnit;
//Step 1: Convert input to celsius
if (StartUnit = 'f')
{
CalcVal = FarCel(StartVal);
}
if (StartUnit = 'k')
{
CalcVal = KelCel(StartVal);
}
if (StartUnit = 'r')
{
CalcVal = RakCel(StartVal);
}
//Step 2: Conver celsius to desired value
cout << CalcVal;
return 0;
}
When I output CalcVal, no matter what, it seems to run through all three functions. It doesn't matter what I type, r, c, f, they all evaluate the same. Could I have some advice on where I'm going wrong?
Solved: Question's answer is that == is used for comparison, my if test used =
Because you seem to assign the values (=), instead of checking them (==). Also you should use else if blocks, for better reading.
All your if-statements assing (=), rather than comparing (==).
So, change this:
if (StartUnit = 'f')
to this:
if (StartUnit == 'f')
and act similar for the rest of the if-statements.
There are three features of C++ that together combine to produce this problem:
In C, C++, and many related language, there is a difference between = (a single equals sign) and == (two equals signs together). The first is an assignment, the second is a comparison. StartUnit = 'f' means "Set StartUnit to the value 'f'"; you meant to use StartUnit == 'f'.
In a lot of languages, and assignment is actually an expression and also has a value. In this case, it's the value assigned, so StartUnit = 'f' means "Set StartUnit to f, and also return the value 'f'". Since it's in an if statement, that both sets StartUnit and does if ('f').
When an if statement or other boolean operation looks at an int, float, char, etc., it checks if they are non-zero. Since 'f' isn't the Nul byte '\x00' (and neither is '0'), it evaluates as true and the if statement body is executed.
Since all of these if statements work the same way, this happens for all of them and all the functions run.
You might also want to use else clauses, or even a switch statement. A bunch of if statements, one after the other, looks like none, any, or all of them could run. Since you want one and only one to happen, you should use else blocks or a switch statement.

C++ const char if-statement

So I'm trying to get this program that will say good or bad depending on your answer and I didn't want to have a really long if and else if statement with a bunch of strings so I put a bunch of possible answers in two chars and I want it to answer depending on what you say. The program only replies to the good answers saying good even if you enter in one of the bad answers.
const char* good[5] = {
"good", "great", "amazing", "amazing!", "fantastic"
};
const char* bad[5] = {
"bad", "bad pal", "bad eugene", "not good", "not good pal"
};
string input01 = "";
int main() {
cout << "Hello" << endl;
system("PAUSE");
system("CLS");
cout << "How are you doing today?" << endl;
cin >> input01;
transform(input01.begin(), input01.end(), input01.begin(), ::tolower);
if (input01 == good[0 > 5] || good[0 < 5]){
system("CLS");
cout << "good" << endl;
system("pause");
}
else if (input01 == bad[0 > 5] || bad[0 < 5]){
system("CLS");
cout << "bad" << endl;
system("pause");
}
}
This: if (input01 == good[0 > 5] || good[0 < 5]) probably doesn't do what you expect (because I can't imagine wanting what it really does).
0 > 5 is evaluated as a test of whether 0 is greater than 5. Since it's obviously not, that produces false. Since it's being used in a context where an integer is needed, that's converted to 0, so that part of the expression becomes if (input01 == good[0].
Likewise, 0 < 5 tests whether 0 is less than 5 (which it obviously is) so the result is true, which converts to 1, so that part of the expression is good[1]. Since that in turn is being used as a Boolean expression, it's treated as equivalent to good[1] != 0.
So what you have overall is if (input01 == good[0] || good[1] != 0).
That seems close enough to useless that I'm pretty sure it's not what you wanted. In particular, good[1] is a pointer. A pointer will compare equal to 0 if and only if it's a null pointer. Since it's initialized to point at something, it's not a null pointer, so that part of the expression will always evaluated as true.
of course, your other if statement is about equally useless.
If you want to check whether input01 is equal to any of the items in good, you might (for one example) use std::find:
if (std::find(std::begin(good), std::end(good), input01) == std::end(good))
// input01 was not present in `good`.
To make that work correctly, you'll want to use std::strings though:
std::vector<std::string> good{"good", "great", "amazing", "amazing!", "fantastic"};
It's kind of pointless for only 5 items, but if you lists of good and bad words are likely to get really large, you'd probably be better off sorting them, then using std::binary_search, or else using std::unordered_set instead.
Try:
if ((strcmp(input.c_str(), good[0]) == 0) ||
(strcmp(input.c_str(), good[1]) == 0) ||
...
(strcmp(input.c_str(), good[4]) == 0))
Or better switch the keywords to strings,
const string good[5] = {
"good", "great", "amazing", "amazing!", "fantastic"
};
and then
if ((input == good[0]) ||
(input == good[1]) ||
...
(input == good[4]))
Or even better, pack the keywords into a set
const set<string> good{"good", "great", "amazing", "amazing!", "fantastic"};
and then
if (good.find(input) != good.end())
Why don't you just check if the input01 is in your array. You should be able to use the find() function to do this. Something like
if(std::find(std::begin(good), std::end(good), input01) != std::end(good))){do something}
You may not need the std:: references

if statements based on user input

I am trying to use different if statements based on user input. However it only seems to use the final set. any help would be great thanks.
char type[20];
double weight;
double feed;
cout<< "Enter horse type: ";
cin>>type;
cout << "Enter the horse weight in whole pounds: ";
cin>>weight;
cout<<"Horse type: "<<type<<endl;
cout<<"Horse weight: "<<weight<<endl;
This is my if statements.
{
if (type=="Light");
if (weight >= 840 && weight <=1200)
feed = (3.0);
else if (weight< 840)
feed = (3.3);
else if (weight > 1200)
feed = (2.5);
}
{
if (type=="Large");
if (weight >= 1100 && weight <=1300)
feed=(3.0);
else if (weight < 1100)
feed=(3.3);
else if (weight > 1300)
feed= (2.5);
}
{
if (type=="Draft");
if (weight >= 1500&& weight <=2200)
feed = (3.0);
else if (weight< 1500)
feed = (3.3);
else if (weight >2200)
feed= (2.5);
}
cout<<"Feed Amount "<<feed<<" pounds"<<endl;
Thanks again for any help
You can't compare C-style strings (character arrays) using ==. That compares the addresses of the arrays, not their contents.
Use std::string instead. Replace the first line with
std::string type;
You also need to fix the if statements:
if (type == "Whatever") // no ;
{
// do stuff
}
Where you have:
{
if (type=="Light");
should be:
if ( type == "Light" )
{
and the same for Draft and Large. What you are actually doing is taking no action regardless of the if, and always executing the following code.
Also ( as noted by Mike Seymour ) change char type[20]; to std::string type;. If you really must stick to char, then you will also need to change your comparison.
If your compiler supports C++14 then:
if ( type == "Light"s )
Otherwise:
if ( type == std::string("Light") )
For any of these cases you need #include <string> at the top of your file.

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.

Accepting a grammar in C++

This is a lab assignment I am stuck on.
I need to accept this grammar (ab)*b, which basically means any number of "ab" and ending with b.
I have written this code but somehow, it checks only the first 2 letters.
#include <iostream.h>
#include <conio.h>
#include <string.h>
enum track {true, false};
void main()
{
clrscr();
char*str;
enum track track_pos, track_pos_2;
cout<<"enter the string: ";
cin>>str;
int len=strlen(str);
cout<<"length of the string is "<<len;
getch();
int i;
for(i=0;i<len; i++)
{
++str;
cout<<"loop"<<i;
if(*str=='a' && i%2==0)
{
cout<<"\nchecking a...";
track_pos=true;
cout<<"\na.check";
++str;
if (*str=='b')
{
cout<<"\nchecking b...";
track_pos=true;
cout<<"\nb.check";
}
else{
track_pos=false;
cout<<"\nb.uncheck";
}
}
}
if(*str=='b')
track_pos_2=true;
else
track_pos_2=false;
if(track_pos==true && track_pos_2==true)
cout<<"\nThe string is accpeted.";
else
cout<<"\nThe string is rejected.";
getch();
cout<<"\n\nDo you want to continue (Y/N)? ";
char ch;
cin>>ch;
if(ch=='y' || ch=='Y')
main();
}
I'm going to regret this, but each time I look at this question I see something else wrong with your code. Here is the line by line. I've probably missed a lot.
The correct name for this header is "iostream", not "iostream.h" - the ".h" version is deprecated. Similarly, use "string", not "string.h" in modern C++, and use the modern STL string classes.
#include <iostream.h>
#include <conio.h>
#include <string.h>
As pointed out, don't do this. You have redefined the standard bool type to have the opposite value from the standard types. I don't even know that this is legal.
enum track {true, false};
The return value of the main function is int, not void.
void main()
{
clrscr();
Do you know what a buffer overflow is? You have defined str as a pointer here, with no allocated memory, and you write to that undefined bit of memory a bit later on. This is undefined behaviour, and you are pretty much guaranteed to crash. I recommend, you should defined str as a std::string - this will nicely avoid the buffer overflow, and it has many useful methods that you can use in your program.
char*str;
enum track track_pos, track_pos_2;
cout<<"enter the string: ";
This is the buffer overflow right here. You are writing to who knows what area of memory.
cin>>str;
If str was a std::string - you would do size_t len=str.length();
int len=strlen(str);
cout<<"length of the string is "<<len;
It's probably not a good idea to mix console IO functions like this with iostreams functions - there are some buffering issues that can lead to difficulties.
getch();
Declare i in the body of the loop, since you aren't using it again. Like so:
for (int i=0; i<len; i++) etc...
int i;
for(i=0;i<len; i++)
{
Instead of using poiter arithmetic, since you are keeping track of the index of the current character in i, just use that and treat str as an array. This way, you don't have to keep str in synch with i all of the way through. This is the cause the bug you are reporting, by the way.
++str;
cout<<"loop"<<i;
You should change this to:
if (str[i]=='a' && i%2==0)
(That works even if str is a std::string by the way, unlike the pointer arithmetic version).
if(*str=='a' && i%2==0)
{
You really should drop out at some point, if you figure out that the string doesn't match, then there is no point going on to the end of the string.
cout<<"\nchecking a...";
I don't favour status flags like this - your code is partly hard to understand because of the proliferation of these flags, you cannot keep track of the proper behaviour. The name track_pos is not mnemonic, that makes it hard to work out what it is meant to signify without detailed study of the code.
I would recommend that you would refactor your code inside the body of the for loop to call a function, the purpose of which is simply to match a single group of "ab" - this function could return true if it did, and false if it did not.
track_pos=true;
cout<<"\na.check";
Note that since we are dealing with the buffer overflow mentioned before, you are iterating undefined memory. Also note that you did not increment i here.
++str;
if (*str=='b')
{
cout<<"\nchecking b...";
track_pos=true;
cout<<"\nb.check";
}
else{
track_pos=false;
cout<<"\nb.uncheck";
}
}
}
When we get to here, according to your for loop, we have iterated the whole string, so we must be looking past the end of the string (even ignoring the buffer overflow) so there is no possible way this test can succeed. In short, your for loop must be going too far.
if(*str=='b')
track_pos_2=true;
else
track_pos_2=false;
if(track_pos==true && track_pos_2==true)
Should I mention the spelling mistake?
cout<<"\nThe string is accpeted.";
else
cout<<"\nThe string is rejected.";
getch();
cout<<"\n\nDo you want to continue (Y/N)? ";
char ch;
cin>>ch;
If you refactor your code into appropriate sub-routines, you will find the structure of the program takes care of itself. Note that calling main recursively is not strictly illegal, but it is kind of weird and has an obvious vulnerability that will lead to an eventual stack overflow, if the program never exits.
if(ch=='y' || ch=='Y')
main();
}
Implement a simple state machine. It has these states:
0 = start
1 = 'received a of (ab)'
2 = 'received b of (ab)'
3 = 'received final b'
-1 = error, invalid grammar
Then you just need a function like this:
int nextState(int currentState, char inputChar) {
if (currentState == 0 && inputChar == 'a') return 1; // handled string is "a"
if (currentState == 0 && inputChar == 'b') return 3; // handled string is "b"
if (currentState == 1 && inputChar == 'b') return 2; // handled string is "ab", or "abab", or ...
if (currentState == 2 && inputChar == 'a') return 1; // handled string is "aba", or "ababa", or ...
if (currentState == 2 && inputChar == 'b') return 3; // handled string is "abb", or "ababb", or ...
return -1;
}
Iterate this "state machine" over your input chars, starting with state 0, and if you end up in state 3, your input is valid.
int isValid(char* inputString) {
int state = 0;
for(int i=0; i<str_len(inputString); i++) {
state = nextState(state, inputString[i]);
}
return (state == 3);
}
Things wrong with your code:
#include <iostream.h>
should be:
#include <iostream>
The following is a non-standard (and very old) header:
#include <conio.h>
The following is illegal - true and false are reserved words.
enum track {true, false};
In C and C++, main must return an int:
void main()
Non standard function:
clrscr();
No memory allocated to this pointer:
char*str;
which is then used here - result undefined behaviour:
cin>>str;
Illegal call to main:
main();
I suspect you are using a very old and obsolete C++ compiler. You should replace it with something like MinGW.
Don't do this!
enum track {true, false};
Here your true is equal to 0 and false is equal to one! When you later assign track_pos, you may get the wrong value! (Because when converting bool to int, true converts to 1 and false converts to 0.)
That's only a guess though. Maybe it's something else that matters.