Validating a string to be all digits - c++

Hi I'm having trouble validating this string to be all decimals, even if I type in 9999 it still tell me my if statement comes out false. I think it's a typo but I don't know where.
cout<<"Enter a very large number"<<endl;
cin>>In1; //inputs a string
for(int i=0; 0<In1.length();i++){ //the loop that goes thru each index
if (!(isdigit(In1[i]))){ //validates each index
//tells the user to try again
cout<<"You did not enter a valid input, please try again"<<endl;
In1="";
cin>>In1;
i=0;//starts the loop over if reached
}
}
I keep receiving the "You did not enter a valid input, please try again" regardless of whether I type it right or wrong.

for(int i=0; 0<In1.length();i++){
See what you did? Change to
for(int i=0; i<In1.length();i++)
In your loop condition you need to compare i with In1.length().

You might want to change
0<In1.length()
to
i<In1.length()

Using
#include<algorithm>
if ( std::find_not_if( in1.begin(), in1.end(), isdigit ) != in1.end() ){ ...
might have prevented this unfortunate incident, and is also quite clear on the intent. The dual _not/!= muddles it slightly but still.
There are quite a few convenience algorithms, replacing common uses for simple for- statements. Most of them are on the form
do_this( where_to_start, where_to_end, do_this_operation )
There is usually nothing special or dramatic with these function, they apply the operation to each element in the start-end sequence.
You have find, count, copy, and generate to mention a few. Their purpose is to clarify the intent of your for-statement. You can find a complete list at http://en.cppreference.com/w/cpp/algorithm

You will almost certainly find that, over time, you become more adept at seperating different parts of code into the functionality that they each provide. Making debugging and later modification considerably easier.
It also makes, as Captain Giraffe points out, the intent of the code considerably more clear - something that can only make reading the code easier & quicker.
I've not used std::find_not_if, opting instead to use the method that you've chosen (based on the assumption that the important thing is knowing how to get the right answer, as opposed to simply supplying the right answer - well, that and me not knowing of find_not_if's existence :grin:) You'll see that I've chucked it into it's own function, which I call from main. The function also only performs a single task - that of checking the validity of the string. Any attempt to prompt the user for this text, re-prompt in the case of error and finally, take action on the correct input is the sole responsibility of the code that calls isValidNumericalString - there's no reason you couldn't throw those functions into their own functions, as opposed to having a single, large body of main.
#include <iostream>
using namespace std;
// returns true if all characters in string are numerical (0-9)
bool isValidNumericalString(string inputString)
{
int i, n = inputString.length();
for (i=0; i<n; i++)
if ( !isdigit(inputString[i]) )
return false;
return true;
}
int main()
{
string In1;
cout << "Enter a very large number (digits 0-9 only. 10e1 is unacceptable): ";
cin >> In1;
while (!isValidNumericalString(In1))
{
cout << "You did not enter a valid input, please try again :p" << endl;
cout << "Enter a very large number (digits 0-9 only. 10e1 is unacceptable): ";
cin >> In1;
}
cout << "Congratulations - '" << In1 << "' is a valid string representation of a number" << endl;
return 0;
}

Related

Trying to ignore all whitespace up to the first character (desperately needing a simple nudge)

I'll be flat out honest, this is a small snippet of code I need to finish my homework assignment. I know the community is very suspicious of helping students, but I've been racking my head against the wall for the past 5 hours and literally have accomplished nothing on this assignment. I've never asked for help on any assignments, but none have given me this much trouble.
All I'm having trouble with is getting the program to strip the leading whitespace out. I think I can handle the rest. I'm not asking for a solution to my overall assignment, just a nudge on this one particular section.
I'll post the full assignment text here, but I am NOT posting it to try to get a full solution, I'm only posting it so others can see the conditions I have to work with.
"This homework will give you more practice in writing functions and also how numbers are read into a variable. You need to write a function that will read an unsigned integer into a variable of type unsigned short int. This will have a maximum value of 65535, and the function needs to take care of illegal numbers. You can not use "cin >>", inside the function.
The rules for numeric input are basically as follows:
1) skip all leading white spaces
2) first character found must be numeric else an error will occur
3) numeric characters are then processed one at a time and combine with number
4) processing stops when non-numeric found
We will follow these rules and also add error handling and overflow. If an illegal entry is made before a numeric than an error code of "1" will be sent back, if overflow occurs, that is number bigger then 65535, then error code of "2" will be sent back. If no error then "0" is sent back.
Make sure the main function will continue to loop until the user enters a “n” or “N” for NO, the main should test the error code returned from the function called “ReadInt” and display appropriate error messages or display the number if there is no error. Take care in designing the “ReadInt” function, it should be value returning and have a reference parameter. The function needs to process one character at a time from the input buffer and deal with it in a correct fashion. Once the number has been read in, then make sure the input buffer is empty, otherwise the loop in main may not work correct. I know this is not how the extraction works, but lets do it this way.
You do not need to turn in an algorithm with this assignment, but I would advise you to write one. And the debugger may prove helpful as well. You are basically rewriting the extraction operator as it works on integers."
A majority of my code won't make sense as I've been deleting things and adding things like crazy to try everything I can think of.
#include <iostream>
#include <CTYPE.h>
using namespace std;
int ReadInt (unsigned short int &UserIn);
int main()
{
int Error;
unsigned short int UserInput;
char RepeatProgram;
do
{
Error=ReadInt(UserInput);
if (Error==0)
cout << "Number is " << UserInput << endl;
else if (Error==1)
cout << "Illegal Data Entry\n";
else if (Error==2)
cout << "Numerical overflow, number too big\n";
cout << "Continue? n/N to quit: ";
cin >> RepeatProgram;
cout << endl;
} while (RepeatProgram!='N' && RepeatProgram!='n');
}
int ReadInt (unsigned short int &UserIn)
{
int Err=0;
char TemporaryStorage;
long int FinalNumber=0;
cout << "Enter a number: ";
//cin.ignore(1000, !' '); this didn't work
cin.get(TemporaryStorage);
cout << TemporaryStorage;//I'm only displaying this while I test my ideas to see if they are working or not, before I move onto the the next step
cout << endl;
return Err;
}
I really appreciate any help I may get and hope I don't give the impression that I'm looking for a full free solution to the whole problem. I want to do this on my own, I'm just lot on this beginning.
As a preface, I want to state that this is a question made by a student, but unlike most of their type, it is a quality question that merits a quality answer, so I'll try to do it ;). I won't try to just answer your concrete question, but also to show you other slight problems in your code.
First of all, let's analyze your code step by step. More or less like what a debugger would do. Take your time to read this carefully ;)...
#include <iostream>
#include <CTYPE.h>
Includes headers <iostream> and <ctype.h> (the uppercase works because of some flaws/design-decisions of NTFS in Windows). I'ld recommend you to change the second line to #include <cctype> instead.
using namespace std;
This is okay for any beginner/student, but don't get an habit of it! For the purposes of "purity", I would explicitly use std:: along this answer, as if this line didn't existed.
int ReadInt (unsigned short int &UserIn);
Declares a function ReadInt that takes a reference UserIn to type unsigned short int and returns an object of type int.
int main()
{
Special function main; no parameters, returns int. Begin function.
int Error;
unsigned short int UserInput;
char RepeatProgram;
Declares variables Error, UserInput, and RepeatProgram with respective types int, unsigned short int, and char.
do
{
Do-while block. Begin.
Error=ReadInt(UserInput);
Assign return value of ReadInt of type int called with argument UserInput of type int& to variable Error of type unsigned short int.
if (Error==0)
std::cout << "Number is " << UserInput << endl;
If Error is zero, then print out UserInput to standard output.
else if (Error==1)
std::cout << "Illegal Data Entry\n";
else if (Error==2)
std::cout << "Numerical overflow, number too big\n";
Otherwise, if an error occurs, report it to the user by means of std::cout.
std::cout << "Continue? n/N to quit: ";
std::cin >> RepeatProgram;
Query the user if he/she wants to continue or quit. Store the input character in RepeatProgram of type char.
std::cout << std::endl;
Redundant, unless you want to add padding, which is probably your purpose. Actually, you're better off doing std::cout << '\n', but that doesn't matters too much.
} while (RepeatProgram!='N' && RepeatProgram!='n');
Matching expression for the do-while block above. Repeat execution of the given block if RepeatProgram is neither lower- or uppercase- letter N.
}
End function main. Implicit return value is zero.
int ReadInt (unsigned short int &UserIn)
{
Function ReadInt takes a reference UserIn to unsigned short int and returns an object of type int. Begin function.
int Err=0;
char TemporaryStorage;
long int FinalNumber=0;
Declares variables Err, TemporaryStorage, and FinalNumber of respective types int, char, and long int. Variables Err and FinalNumber are initialized to 0 and 0, respectively. But, just a single thing. Didn't the assignment said that the output number be stored in a unsigned short int? So, better of this...
unsigned short int FinalNumber = 0;
Now...
std::cout << "Enter a number: ";
//std::cin.ignore(1000, !' '); this didn't work
Eh? What's this supposed to be? (Error: Aborting debugger because this makes no logic!**). I'm expecting that you just forgot the // before the comment, right? Now, what do you expect !' ' to evaluate to other than '\0'? istream::ignore(n, ch)will discard characters from the input stream until either n characters have been discarded, ch is found, or the End-Of-File is reached.
A better approach would be...
do
std::cin.get(TemporaryStorage);
while(std::isspace(TemporyStorage));
Now...
std::cin.get(TemporaryStorage);
This line can be discarded with the above approach ;).
Right. Now, where getting into the part where you obviously banged your head against all solid objects known to mankind. Let me help you a bit there. We have this situation. With the above code, TemporaryStorage will hold the first character that is not whitespace after the do-while loop. So, we have three things left. First of all, check that at least one digit is in the input, otherwise return an error. Now, while the input is made up of digits, translate characters into integers, and multiply then add to get the actual integer. Finally, and this is the most... ahem... strange part, we need to avoid any overflows.
if (!std::isdigit(TemporaryStorage)) {
Err = 1;
return Err;
}
while (std::isdigit(TemporaryStorage)) {
unsigned short int OverflowChecker = FinalNumber;
FinalNumber *= 10; // Make slot for another digit
FinalNumber += TemporaryStorage - '0'; '0' - '0' = 0, '1' - '0' = 1...
// If an unsigned overflows, it'll "wrap-around" to zero. We exploit that to detect any possible overflow
if (FinalNumber > 65535 || OverflowChecker > FinalNumber) {
Err = 2;
return Err;
}
std::cin.get(TemporaryStorage);
}
// We've got the number, yay!
UserIn = FinalNumber;
The code is self-explanatory. Please comment if you have any doubts with it.
std::cout << TemporaryStorage;//I'm only displaying this while I test my ideas to see if they are working or not, before I move onto the the next step
cout << endl;
return Err;
Should I say something here? Anyway, I already did. Just remember to take that std::couts out before showing your work ;).
}
End function ReadInt.
You can skip leading whitespace from a stream using std::ws. For example:
std::cin >> std::ws;
This use of >> just invokes the manipulator std::ws on the stream. To meet the teacher's requirements you can invoke it directly:
std::ws(std::cin);
Formatted input automatically skips whitespace. Note that should also always check whether input was successful:
if (std::cin.get(TemporaryStorage)) {
...
}

Storing data from a text file in an array of structures C++

I am attempting to read data from a text file into an array of structures. The first iteration of the for-loop reads and displays everything correctly until it reaches the Boolean value, and every iteration after that does not display as expected. Is the bool value at the end causing the entire rest of the file to be read incorrectly? Or perhaps an issue stemming from getline?
int main()
{
groceryProduct inventoryDatabase[25];
ifstream fin("inventory.txt");
if (!fin)
{
cout << "File could not be located.";
}
string itemName;
for (int index = 0; index < 25; index++)
{
getline(fin, inventoryDatabase[index].itemName, '\n');
fin >> inventoryDatabase[index].itemNumber;
fin >> inventoryDatabase[index].itemPrice;
fin >> inventoryDatabase[index].membershipPrice;
fin >> inventoryDatabase[index].payByWeight;
cout << inventoryDatabase[index].itemName << endl;
cout << inventoryDatabase[index].itemNumber << endl;
cout << inventoryDatabase[index].itemPrice << endl;
cout << inventoryDatabase[index].membershipPrice << endl;
cout << inventoryDatabase[index].payByWeight << endl;
}
return 0;
};
The structure:
struct groceryProduct
{
double itemPrice;
double membershipPrice;
double itemWeight;
int itemQuantity;
string itemNumber;
string itemName;
bool payByWeight;
};
The output:
Apple
P0000
0.85
0.8
204 (expected output of 'false' instead of 204)
Output for every iteration of loop after first iteration:
-9.25596e+61
-9.25596e+61
204
Thank you, and please let me know if you require any more information.
File:
Apple
P0000
.85
.80
false
Orange
P0001
.95
.85
false
Lemon
P0002
.65
.60
false
You need to tell your stream that the bool values are text with
fin >> boolalpha >> inventoryDatabase[index].payByWeight
You're seeing garbage data after the first bool input because failbit gets set in the stream and no further inputs will work until it is reset. This results in you array's data staying uninitialized.
Here are a couple of things I see that may be causing your problem.
1) An array is not "magically filled" with data. You have an uninitialized array, meaning that the data inside of it does not yet exist. At all.
What you have to do to remedy this is to add a new instance of the struct to the array at the start of each loop iteration.
How'd I spot that? Good rule of thumb: if it's weird, it's memory-related. Make sure you've initialized everything.
2) I've seen weird things happen when you use getline and << next to each other. Is there a particular reason you are using getline over <<?
(I would need to re-research how to work around that weirdness. I used to hit it a lot in my C++ class way back when.)
3) What 1201ProgramAlarm said is absolutely correct.
Side note: Do NOT get into the habit of throwing double around because "I want to be able to arbitrarily throw a large value in there." It's a bad habit that wastes space, as double is twice as large as float.
Learn the difference between float and double - you will almost never need double outside of scientific situations, because it is for numbers with a LOT of decimal places. (That's oversimplifying it.) If you're using double over float all the time, you're using twice the memory you need - 32 bits per variable extra, in fact. It adds up. (And people wonder why modern programs need 8GB of RAM to do the same thing as their 100MB-RAM-using predecessors...)
Prices always have two (rarely three) decimal places, so float should fit that perfectly in all cases. Same with weights.

Visual C++ using Console: Char/String compatibility issues with while loop

cout << "Would you like to make another transaction? (y/n)" << endl;
cin >> repeat_transaction;
static_cast<char>(repeat_transaction);
while (repeat_transaction != 'y' && repeat_transaction != 'n')
{
cout << "Invalid selection: Please enter y or n";
cin >> repeat_transaction;
static_cast<char>(repeat_transaction);
}
During the Invalid selection loop, I once accidentally pressed "mn". I noticed the console read out Invalid selection..., So, it did in fact finish and re-enter the while loop. However, after this the console terminated the program. If you enter a single character 'a' or 'y' or 'n' it acts just as it should. Ending or not ending. This was before I attempted to use static_cast to force the truncation of the user input.
Since you managed to get this program to compile I can only assume that repeat_transaction was specified as a char and not a std::string.
When you use cin to get a character it only gets one character but it doesn't flush the buffer. I believe you understand this issue since you wrote This was before I attempted to use static_cast to force the truncation of the user input. . You can attempt to use cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); instead of static_cast<char>(repeat_transaction); after each call to cin >> repeat_transaction; . There are downsides to this. If you enter 'mn' it will work as expected. It reads the m which is not y or n and then flushes the extra characters until it finds end of line \n. If you do nm, n will match and the m will be thrown away. So in that case it will accept nm as valid and exit the loop.
There are other ways that may be easier and give you the effect closer to what you are looking for. Instead of reading a character at a time you can read an entire line into a string using getline (See the C++ documentation for more information). You can then check if the length of the string is not equal to 1 character. If it's not length 1 then it is invalid input. If it is 1 then you want to check for y and n. Although basic (and not overly complex) this code would do a reasonable job:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string repeat_transaction;
cout << "Would you like to make another transaction? (y/n)" << endl;
getline(cin, repeat_transaction);
while (repeat_transaction.length() != 1 || (repeat_transaction != "y" && repeat_transaction != "n"))
{
cout << "Invalid selection: Please enter y or n";
getline(cin, repeat_transaction);
}
return 0;
}
I said reasonable job since one deficiency you might see is that you want to trim white spaces from the beginning and end. If someone enters n or y with a space or tab in front it will be seen as invalid (whitespace at the end would be similar). This may not be an issue for you, but I thought I would mention it.
On a final note, you may have noticed I used using namespace std;. I did so to match what was in the original question. However, this is normally considered bad practice and should be avoided. These StackOverflow answers try to explain the issues. It is better to not do it and prepend all standard library references with std::. For example string would be std::string, cin would be std::cin etc.

Check if "cin" is a string

I have a simple little script I am coding, and I am trying to not allow people to enter a string, or if they do make it revert to the beginning of the function again. Here's the input code I have:
int main()
{
cout << "Input your first number" << endl;
cin >> a;
cout << "Input your second number" << endl;
cin >> b;
}
The rest of the code beyond this part works just fine for what's going on, although if a string is entered here it obviously doesn't work.
Any help would be appreciated.
You may find this post useful,
How to check if input is numeric in C++
Basically you can check the input, whether it is numeric value or not. After checking whether the given input is numbers, then you can add a while loop in main to ask user to repeat if input is not a valid number.
Every input is a string. If you want to know if a entered string can convert to a number, you have to read in a string and try to convert it yourself (eg with strol).
An alternative would be to check if the reading from cin failed, but personally i don't like it because cin.fail() covers more error situations than just a failed type conversion.
There's a library function may help,you can check it after input:
int isdigit(char c);
Tips:
1.You should include such files :
# include <ctype.h>
2.If c in 0 ~ 9 ,return 1 ; else return 0.

Trying to use a while statement to validate user input C++

I am new to C++ and am in a class. I am trying to finish the first project and so far I have everything working correctly, however, I need the user to input a number to select their level, and would like to validate that it is a number, and that the number isn't too large.
while(levelChoose > 10 || isalpha(levelChoose))
{
cout << "That is not a valid level" << endl;
cout << "Choose another level:";
cin >> levelChoose;
}
That is the loop I made, and it sometimes works. If I type in 11 it prints the error, and lets me choose another level. However if the number is large, or is any alpha character it floods the screen with the couts, and the loop won't end, and I have to force exit. Why does it sometimes stop at the cin and wait for user input, and sometimes not? Thanks for the help!
This is an annoying problem with cin (and istreams in general). cin is type safe so if you give it the wrong type it will fail. As you said a really large number or non-number input it gets stuck in an infinite loop. This is because those are incompatible with whatever type levelChoose may be. cin fails but the buffer is still filled with what you typed so cin keeps trying to read it. You end up in an infinite loop.
To fix this, you need to clear the fail bit and ignore all the characters in the buffer. The code below should do this (although I haven't tested it):
while(levelChoose > 10 || isalpha(levelChoose))
{
cout << "That is not a valid level" << endl;
cout << "Choose another level:";
if(!(cin >> levelChoose))
{
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
Edit: numeric_limits<> is located in the limits include:
#include<limits>
From your description, it seems likely (nearly certain) that levelChose is some sort of numeric type, probably an integer.
When you use operator>> to read a number, anything that couldn't be part of a number (e.g., most letters) will be left in the input buffer. What's happening is that you're trying to read the number, it's failing and leaving the non-digit in the buffer, printing out an error message, then trying to read exactly the same non-digit from the buffer again.
Generally, when an input like this fails, you want to do something like ignoring everything in the input buffer up to the next new-line.
levelChoose appears to be an integer type of some form (int, long, whatever).
It's not valid to input a character into an integer directly like that. The input fails, but leaves the character in the incoming buffer, so it's still there when the loop comes around again.
Here's a related question: Good input validation loop using cin - C++
I suspect the part while(levelChoose > 10..... This does not restrict level to less than 10 (assuming greater than 10 is a large number in your context). Instead it probably should be while(levelChoose < 10...
To check that an expression is not too large, the following could be a possibility to validate (brain compiled code!!)
const unsigned int MAX = 1000;
unsigned int x;
cin >> x;
while(x < MAX){}