Need help on reading a character from a string - c++

My program is supposed to ask the user to input their credit card number and then display whether the numbers are valid or invalid and if valid ,display the card type. I'm having trouble trying to read the first 2 characters in the cardNumber string in order to find out whether the card type is visa,mastercard,american express or discover (4 for visa, 5 for mastercard, 37 for american express, 6 for discover)
#include <iostream>
#include <string>
using namespace std;
int main()
{
string cardNumber; //this will carry the number given by the user.
int sum(0), sumOfDoubleEven(0), sumOfOdd(0), evenDigit(0), oddDigit(0);
cout << "This program is the Credit Card Number Validator." << endl;
cout << "This program will check the validity status of your card number" << endl;
//Main loop
do
{
cout << endl << "Please provide a number to validate or type 'n' to quit ";
cin >> cardNumber; //gets cardNumber from user
if(cardNumber.length()>=13 && cardNumber.length()>=16)
{
if (cardNumber == "n") break; //exits loop on user request
//this for loop repeats once for each digit of the cardNumber.
//digitPosition decrements by one on each pass from last position to first position
for (int digitPosition=cardNumber.length(); digitPosition>0; digitPosition--)
{
if (digitPosition%2 == 0)
{ //executes the following code if digitPosition is even
oddDigit=(int)cardNumber[digitPosition-1]-'0';
sumOfOdd=sumOfOdd+oddDigit;
} else { //executes the following code if digitPosition is odd.
evenDigit=((int)cardNumber[digitPosition-1]-'0')*2;
evenDigit=evenDigit%10+evenDigit/10;
sumOfDoubleEven=sumOfDoubleEven + evenDigit;
}
}
sum=sumOfOdd+sumOfDoubleEven; //sums the result
cout << endl <<"The number "<<cardNumber<<" you provided is ";
if (sum%10==0) //executes if sum is divisible by 10
cout << "valid" << endl;
else //executes if sum is not divisible by 10
cout << "invalid" << endl;
if(cardNumber.at(0)==4) {
cout<<"Your Card type is VISA"<<endl;
} else {
cout<<"Sorry, you've entered a card number not in the range of 13-16 digits" <<endl;
}
}
}while (cardNumber != "n");
return 0;
}

There are some odd parts in your code, but the problem is you are testing the first digit against a number while your digit is stored in a string. So the test should be if (cardNumber.at(0) == '4') ....

One of your problems is that you get the first character (at position 0) and compare it to an int. The value of a character, while an integer, is the value the character have in the current encoding. For example, in ASCII encoding (which is the most common) the character '4' has the value 52.
So that's why the comparison cardNumber.at(0)==4 will fail, because 4 is not equal to '4'.

if (cardNumber[0] == '4') {
// VISA
} else if (cardNumber[0] == '5') {
// mastercard
} else if (cardNumber[0] == '6') {
// discover
} else if (cardNumber[0] == '3' && cardNumber[1] == '7') {
// American Express
} else {
// Invalid card type
}
By the way, your card number length verification condition is not what you expect, it should be
if (cardNumber.length() >= 13 && cardNumber.length() <= 16) {...}

Related

When the input is a character or a word, it doesn't display "Invalid input"

When the input is >2 or <0 it display "Invalid input.". But when the input is an alphabet or a word it does not display "Invalid input."
int main()
{
int userInput, gesture;
cout << "Rock(0), Paper(1), Scissor(2): ";
cin >> userInput;
srand(time(0));
gesture = rand() % 3;
if (isdigit(userInput) && userInput >= 0 || userInput <= 2) //I think it's a logic error, but idk how to fix it.
{
switch (gesture)
{
case (0):
if (userInput == gesture)
cout << "The computer is rock. You are rock too. It is a draw." << endl;
else if (userInput == 1 && gesture == 0)
cout << "The computer is rock. You are paper. You win." << endl;
else if (userInput == 2 && gesture == 0)
cout << "The computer is rock. You are scissor. You lose." << endl;
break;
}
}
else
cout<<"Invalid input.";
return 0;
}
Let's look at this:
if (isdigit(userInput) && userInput >= 0 || userInput <= 2)
The signature of isdigit is this:
int isdigit( int ch );
so one might be fooled into thinking that it expects an int, like 1 or 34. In reality, it expects an argument of type unsigned char converted into an int. Why, you'd ask? Because it was included into C++ via the standard library of the C language, and in C there's a special marker EOF that marks the "end of file" in a stream of characters (just like \0 marks the end of a string). The problem is that EOF cannot be represented as a char, hence many C functions designed to handle strings accept ints. The only thing we know about EOF is that it is negative.
So, the usual usage of isdigit is something like this:
unsigned char c = '0';
// ...
if (isdigit(c)) { /* ... */ }
What you should do, then?
Well, the simpler, the better
if (userInput >= 0 && userInput <= 2)
If you want to check for completely invalid user input, check the state of cin
if (std::cin && userInput >= 0 && userInput <= 2)
An alternative is to initialize userInput with a plain wrong value, e.g. with -1. If cin fails, you'll know something wrong has happened anyway, because userInput woul'd have an ivalid value -1.
Use std::cin.clear() to clear the "fail state" flag in std::cin and unblock it.

How can I get an if-statement that takes multiple cin inputs to recognize an error if only the first cin input is incorrect?

I am building a program that is meant to store values from day-of-week/value pairs into a vector, and then display and sum the values for each day of the week. Therefore, I am asking the user to enter both a string (day of the week, which can be in 4 different forms for each day of the week) and an integer (a corresponding value) for each cin input. (The program only shows Monday and an exit condition so far; I will later build it out to include Tuesday through Sunday as well.)
The program is also meant to identify incorrect input (and allow the user to retry their input). However, I am having trouble getting the program to recognize erroneous input if only the day of week is entered incorrectly. For instance, the program will successfully announce "Incorrect day of week detected" if I enter "test test" as the input. It will also announce this message (even though the wording needs to be tweaked) if I enter "Monday x." However, if I enter "Test 5," the program accepts this without displaying the "Incorrect day of week" message.
How would it be possible to change my program so that, using the pre-existing else statement, it displays "Incorrect day of week" when I enter something like "Test 5"?
One solution would be to create a very long if statement that displays this message if the day of week entered does not match any of the 29 valid day-of-week entries (e.g. "Monday," "monday," "Mon," "mon," "Tuesday," "tuesday" . . . ). However, I would like to find a simpler approach.
Thank you for your help!
#include "../std_lib_facilities.h"
#include <iostream>
//Program in progress. Completing as part of my independent study of Programming: Principles and Practice by Bjarne Stroustrup.
int main()
{
string dayofweek;
int value;
vector<int> mondayvalues;
vector<int> tuesdayvalues;
vector<int> wednesdayvalues;
vector<int> thursdayvalues;
vector<int> fridayvalues;
vector<int> saturdayvalues;
vector<int> sundayvalues;
int incorrectentrycounter = 0;
int mondaysum = 0;
cout << "Please enter days of the week followed by values in integer form. When you are finished, please enter Done 0.\n";
string incorrectnumdump;
while (cin) {
if (cin >> dayofweek >> value) {
if (dayofweek == "Monday" || dayofweek == "monday" || dayofweek == "Mon" || dayofweek == "mon") {
mondayvalues.push_back(value);
}
if ((dayofweek == "Done") && (value == 0)) {
break;
}
}
else {
cin.clear();
cin >> incorrectnumdump;
cout << "Incorrect day of week detected; please try again.\n";
incorrectentrycounter++;
continue;
}
}
cout << "Here are the values you entered for each day of the week, along with their sums:\n";
cout << "Monday: ";
for (int x : mondayvalues)
cout << x << " ";
for (int i = 0; i < mondayvalues.size(); i++) {
mondaysum += mondayvalues[i];
}
cout << "\nSum of Monday values: " << mondaysum;
cout << "\nThere were " << incorrectentrycounter << "entries that displayed non-valid days of the week.";
}
Hmm.. Maybe you can use an ASCII technique to internally flip all inputs to either all caps or all small letters so that you won't have to look for both cases in your if statements as long as caps or small letters doesn't matter.
Make a function that takes the inputs and converts them to all caps or all small. Use this function before assigning the inputs to your variables. This will make checking them easier.
After that, you could create a const array[7] of std::string that will include all days. You can check your inputs by a method of elimination. You will be comparing input and array days letter by later and eliminating the days that don't match each time. If all days are eliminated then wrong input. If 2 or more days remain - input not sufficient. If 1 day remains that's the correct input!
Lemme know if you need help
After playing around with the code, I settled on this solution, which I think will meet my needs. The code now has two invalid entry statement blocks instead of one. The first ("Incorrect day of week detected") is within the if (cin >> dayofweek >> value) condition, and will identify dayofweek entries that don't match one of the Monday strings or Done.
The second ("Invalid entry") is outside the if (cin >> dayofweek >> value) condition but within the while (cin) condition. I added this second one so that if someone enters something like "test test," they will be notified of the error but the while loop will still continue.
So it seems as though when the user needs to enter multiple values via cin >>, one approach to input validation can be to enter multiple error messages at different levels of the code.
This solution is still a little clunky, but allows me to capture invalid entry with just "else" {} rather than "else" followed by a long set of conditions.
#include "../std_lib_facilities.h"
#include <iostream>
//Program in progress. Completing as part of my independent study of Programming: Principles and Practice by Bjarne Stroustrup.
int main()
{
string dayofweek;
int value;
vector<int> mondayvalues;
vector<int> tuesdayvalues;
vector<int> wednesdayvalues;
vector<int> thursdayvalues;
vector<int> fridayvalues;
vector<int> saturdayvalues;
vector<int> sundayvalues;
int incorrectentrycounter = 0;
int mondaysum = 0;
cout << "Please enter days of the week followed by values in integer form. When you are finished, please enter Done 0.\n";
string incorrectnumdump;
while (cin)
{
if (cin >> dayofweek >> value)
{
if (dayofweek == "Monday" || dayofweek == "monday" || dayofweek == "Mon" || dayofweek == "mon")
{
mondayvalues.push_back(value);
}
else if ((dayofweek == "Done") && (value == 0))
{
break;
}
else
{
cin.clear();
cin.ignore(10000, '\n');
cout << "Incorrect day of week detected; please try again.\n";
incorrectentrycounter++;
continue;
}
}
else
{
cin.clear();
cin.ignore(10000, '\n');
cout << "Invalid entry; please try again.\n";
incorrectentrycounter++;
continue;
}
}
cout << "Here are the values you entered for each day of the week, along with their sums:\n";
cout << "Monday: ";
for (int x : mondayvalues)
cout << x << " ";
for (int i = 0; i < mondayvalues.size(); i++)
{
mondaysum += mondayvalues[i];
}
cout << "\nSum of Monday values: " << mondaysum << "\n";
cout << "\nThere were " << incorrectentrycounter << " invalid entries.";
}

C++ Checking Against Particular Numbers

Hello Dear Programmers,
I've been working on a piece of code for a while, but I don't seem to figure this out, i'm trying so hard to check an input with a specific number, but so far it ends up not working and even when number 2,3, or 4 is pressed the error message pops up, and I go to my if else condition. here are the codes, number_of_bedrooms is an integer.
out << "Number Of Bedrooms: (Limited To 2,3, and 4 Only)" << endl;
if (isNumber(number_of_bedrooms) == false ) {
cout << "Please Do Enter Numbers Only" << endl;
cin.clear();
}
else if (number_of_bedrooms != '2' || number_of_bedrooms != '3' || number_of_bedrooms != '4') {
cout << "Numbers Are Only Limited To 2,3, And 4" << endl;
cin.clear();
}
and the function :
bool isNumber(int a)
{
if (std::cin >> a)
{
return true;
}
else
{
return false;
}
}
the first validation which checks for numbers works fine, but the second validation no, my guess is the system is not capturing inputted data after that boolean function. And if that's the reason, what's the solution ?!!
Change your || to &&, also you need to compare to int not char
else if (number_of_bedrooms != 2 && number_of_bedrooms != 3 && number_of_bedrooms != 4)
Note that a more general way to solve such a problem (for example if your list got much longer) would be to do something like
std::set<int> const allowableBedrooms = {2,3,4};
else if (allowableBedrooms.find(number_of_bedrooms) == allowableBedrooms.end())
{
// Warn user here
}
As your goal conditions are sequential, I'd use something like this:
else if ( number_of_bedrooms < 2 || number_of_bedrooms > 4 ) {
cout << "Numbers Are Only Limited To 2,3, And 4" << endl;
cin.clear();
}
This is very clear and easy to manage if you want to change it. If you want to enumerate everything you'll need to use && instead of || since your want it to both be not 2 and not 3 and not 4 to trigger the issue.
Another problem in your code is that you're comparing against characters by putting the numbers in single quotes. Since these are integers you should not have them in quotations.
You have to change your function to make the change out of the local function like this:
bool isNumber(int * a)
{
if (std::cin >> * a)
{
return true;
}
else
{
return false;
}
}
And then call the function with the address of number_of_bedrooms like this:
out << "Number Of Bedrooms: (Limited To 2,3, and 4 Only)" << endl;
if (isNumber(&number_of_bedrooms) == false ) {
cout << "Please Do Enter Numbers Only" << endl;
cin.clear();
}
else if (number_of_bedrooms < 2 || number_of_bedrooms > 4) {
cout << "Numbers Are Only Limited To 2,3, And 4" << endl;
cin.clear();
}
Check the code above becouse i took off the '' that means you are comparing number_of_bedrooms (int) with '2' (char) so it will be always true.
The condition i wrote would be better then becouse you are considering an interval of numbers, if you are considering the specific numbers you can leave your condition but you should change the logical operator in && and chain with the other != conditions

C++ mystical infinite loop

I just started learning C++ after previously coding with Java. The code below takes input from the user and validates the input. The first piece asks for the number of voters, which must be a positive number. If I enter a negative number the program behaves as I expected. It prints out the error message and asks for the input again. However, if I enter any other character, such as any alphabet letter I get an infinite loop in the console, asking for input and printing the error message. What am I doing wrong?
my code:
#include <iostream>
using namespace std;
struct dataT {
int numOfVoters = -1;
float preSpread = -1;
float votingError = -1;
};
void getUserInfo() {
dataT data;
while (data.numOfVoters == -1) {
cout << "enter the number of voters" << endl;
cin >> data.numOfVoters;
if (data.numOfVoters <= 0) {
data.numOfVoters = -1;
cout << "Invalid entry, please enter a number larger than zero." << endl;
}
}
while (data.votingError == -1) {
cout << "enter the percentage spread between candidates" << endl;
cin >> data.votingError;
if (data.votingError <= 0 || data.votingError >= 1) {
data.votingError = -1;
cout << "Invalid entry. Enter a number between 0 to 1." << endl;
}
}
while (data.preSpread == -1) {
cout << "Enter the precentage spread between the two candidates." << endl;
cin >> data.preSpread;
if (data.preSpread <= 0 || data.preSpread >= 1) {
data.preSpread = -1;
cout << "Invalid input. Enter a number between 0 and 1." << endl;
}
}
}
int main() {
getUserInfo();
return 0;
}
Console:
enter the number of voters
f
Invalid entry, please enter a number larger than zero.
enter the number of voters
Invalid entry, please enter a number larger than zero.
enter the number of voters
Invalid entry, please enter a number larger than zero.
...
...
...
If you write cin >> integervariable but in cin there are character that cannot represent an integer, the input fails, !cin becomes true, and the character remain there until you don't reset the input state from the error and consume the wrong characters.
a proper check can be
while(integervariable has not good value)
{
cout << "prompt the user: ";
cin >> integervariable;
if(!cin) //something wrong in the input format
{
cin.clear(); //clear the error flag
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discard the rubbish
cout << "prompt error message \n";
}
}
Your if statements are always true, you want something more like:
if (data.votingError < 0 || data.votingError > 1) {
...
then data.votingError can take on a value different from -1 and exit your loop.
The std::cin object will check whether or not it is in a valid state every time it reads. If you enter a char where your program expects an int, then you'll "break" the input stream. All subsequent calls to std::cin will then be effectively skipped until you manually reset the input stream. When this happens, you'll never be able to set your values to anything other than -1, and your if statement always evaluates to true, causing an infinite loop.
As an aside, you can check for failure state by including && cin in all of your tests. Input objects implicitly evaluate to true if the stream is in a valid state and to false if the stream is in a failure state instead.

Infinite while loop happens when asking user for 2 numbers

I'm trying to implement a simple game where user is asked for 2 valid integer coordinates between 0 and 10. (int row, int column)
An exemple of what I would realize is:
Insert coordinates: 4C
*Error, number of row and column must be integer
Insert coordinates: 44 2
*Error, number of row or column are too high
Insert coordinates: 4 3
The coordinates you entered are (4,3)
I realized all of these with a do-while cycle.
int r,c;
do{
cout<<"Insert coordinates: ";
cin>>r>>c;
if (cin.fail())
{
cout << "ERROR: Number of row and column must be integer." << endl << endl;
}
if ((r<0 || r>10) || (c<0 || c>10)
{
cout << "*Error, number of row or column are too high [0-10]" << endl << endl;
}
cout<<endl;
}
while (((r<0 || r>10)||(c<0 || c>10)) || cin.fail());
This code doesn't work properly. If I enter 2 numbers between 0 and 10, it works. If I enter a number bigger then 10, it also works. But if I entered a character the program goes into an infinite loop, and does not work properly.
How to implement this to handle errors with character input? Is there a way to recognize, and remain inside the while cycle, if user inputs a character?
If you enter a letter instead of a number, then that letter is not extracted from the input buffer, so your code will continue to fail forever.
If the input fails (why not use e.g. if (!(cin >> r >> c))?) then you can skip the line by doing calling the ignore function:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
You also want to clear the failbit as it's not cleared automatically, this is done with the clear function.
You can also bypass this problem by getting the whole line, and using std::istringstream for the parsing:
do
{
std::string line;
if (!std::getline(std::cin, line))
... // Could not read from input
std::istringstream iss(line);
int r, c;
if (!(iss >> r >> c))
... // Failed to parse as numbers
...
} while (...);
You could simply check if characters were entered, for example:
if (x >= 0x41 && x <= 0x7A)
cout<<"error, you entered a letter";
(((r<0 || r>10)||(c<0 || c>10)) || cin.fail());
change to
(((r>0) && (r<10))||((c>0) && (c<10))) //It will work, no need to check cin.fail();
If cin fails then it might produce errors in buffer so better to quit the program..
The program goes into an infinite loop because you never clear the fail state. You can simplify your entire loop:
#include <iostream>
using namespace std;
int main()
{
int r = -1;
int c = -1;
bool valid = false;
do
{
cout<<"Insert coordinates: ";
if (cin >> r >> c)
{
if (r >= 0 && r <= 10 && c >= 0 && c <= 10)
{
valid = true;
}
}
else
{
cin.clear();
cin.ignore();
}
if (!valid)
{
cout << "ERROR: Number of row and column must be an integer between 0 and 10." << endl;
}
} while (!valid);
cout << "You entered (" << r << ", " << c << ")" << endl;
return 0;
}