I'm creating my own very simple program that allows the user to input a numeric value. At the moment the code works just fine, but I need a validation if else statement. This is what I have at the moment;
#include <iostream>
#include <string>
using namespace std;
int main()
{
unsigned __int64 input = 0;
char str[] = "qwertyuiopasdfghjklzxcvbnm[]{};'#:#~,./<>?|!£$%^&*()";
cout << "Insert a number" << endl;
cin >> input;
if (input % 2 == 0)
{
cout << "Even!" << endl;
}
else
{
if (input% 2 == 1)
{
cout << "Odd" << endl;
cout << "Lets make it even shall we? " << "Your new number is... " << input + 1 << endl;
}
else if (isdigit(str[0]))
{
cout << "That isn't a number!" << endl;
}
}
system("pause");
return 0;
}
The issue I am having is that if the user inputs anything that isn't a number, the value it returns is "Even".
I hope you guys and girls can help!
John
Don't use token extraction (>>) for primary parsing. Once the extraction fails, your primary input is left in an unspecified state, which is terrible. Instead, read the input line by line and then process each line.
Also, never ignore the result of an input operation. That's just a flat error.
So, putting all this together, here's how you could handle this:
#include <iostream>
#include <sstream>
#include <string>
int main()
{
for (std::string line; std::cout << "Input: " && std::getline(std::cin, line); )
{
std::cout << "We're parsing your line '" << line << "'\n";
int n;
std::istringstream iss(line);
if (iss >> n >> std::ws && iss.get() == EOF)
{
std::cout << "It was a number: " << n << "\n";
}
else if (line.empty())
{
std::cout << "You didn't say anything!\n";
}
else
{
std::cout << "We could not parse '" << line << "' as a number.\n";
}
}
std::cout << "Goodbye!\n";
}
Note that all input operations (namely >> and getline) appear in immediate boolean contexts!
Related
#include <iostream>
int main() {
int fav_num {0};
bool in_range {false};
while (in_range == false) {
std::cout << "Enter your favorite number between 1 and 100: ";
std::cin >> fav_num;
if (fav_num < 1 || fav_num > 100 || !std::cin ) {
std::cout << "===Ops!, invalid choice, please try again.===" << std::endl;
std::cin.clear();
std::cin.ignore();
}
else {
std::cout << "Amazing!! That's my favorite number too!" << std::endl;
std::cout << "No really!!, " << fav_num << " is my favorite number!" << std::endl;
in_range = true;
}
}
std::cout << "==================================================" << std::endl;
return 0;
}
Why am I getting my output many times?
Once for q, once for w, once for e.
Check the docs for std::basic_istream::ignore. Without parameter, it skips only one character, so your loop will go through each character once, before it accepts new input again.
You want std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); to ignore every character until the next line.
I'm trying to write a program that reads input as int from the command line, and if the user enters an int, program prints "Input is " + the number if users enter an incorrect type input, output "wrong input".
Here is my code:
#include <iostream>
#include <string>
using namespace std;
int main() {
int input;
cout << "Enter an Int:" << endl;
cin >> input;
if (!(cin >> input)) {
cout << "wrong format input" << endl;
return 1;
}
cout << "input is " << input << endl;
return 0;
}
Now with cin >> input; (case-1) program asks for twice input when enter correct integer; it prints "wrong format input" if user enter '2.2' or 'a'.
Without cin >> input; (case-2) program ask for once input when enter correct integer; but it prints "input is 2" when user enter '2.2', instead of printing "wrong" message, program prints "Input is 2".
Which part in my code did I make mistake? How can I fix this?
For case-2:
Here is the sample that allows to enter several integers on the same line, but disallows anything else
#include <iostream>
#include <string>
int main()
{
std::string input;
while(std::cin >> input){
size_t last;
int res;
bool good = true;
try{
res = std::stoi(input,&last);
}
catch(...){
good = false;
}
if(!good || last != input.length()){
std::cout << "Incorrect input: " << input << ", try again.\n";
}
else{
std::cout << "Integer read: " << res << '\n';
}
}
return 0;
}
/***************
Output
$ ./test
2
Integer read: 2
hello
Incorrect input: hello, try again.
2.2
Incorrect input: 2.2, try again.
1111111111111111111111111111111111111111111111111111111111111111111111
Incorrect input: 1111111111111111111111111111111111111111111111111111111111111111111111, try again.
3 4
Integer read: 3
Integer read: 4
^Z
[3]+ Stopped ./test
*/
Another version - using stringstream
while(std::cin >> input){
std::istringstream ss(input);
int res;
ss >> res;
if(!ss){
std::cout << "Incorrect input: " << input << ", try again.\n";
}
else{
char ch = ss.get();//let's check that no more characters left in the string
if(!ss){
std::cout << "Integer read: " << res << '\n';
}
else{
std::cout << "Incorrect input: " << input << ", try again.\n";
}
}
}
if(!(cin >> input)) is the reason for the second input. Just do this:
#include <iostream>
#include <string>
using namespace std;
int main() {
int input;
cout << "Enter an Int:" << endl;
cin >> input;
if (cin.fail()) {
cout << "wrong format input" << endl;
return 1;
}
cout << "input is " << input << endl;
return 0;
}
This is the program:
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
int main(){
string strKingdom = "";
bool conquered_me;//see if was conquered, was going to use this on other program and true = game over.
int gold;
int food;
int citizens;
int soldiers;
cout << endl <<"Name of kingdom: ";
cin >> strKingdom;
cout << endl << "were you conquered (true/false): ";
cin >> conquered_me;
cout << endl << "How many gold do you have?:";
cin>>gold;
cout << endl << "How many food do you have?:";
cin >> food;
cout << endl << "How many citizens do you have?:";
cin >> citizens;
cout << endl << "How many soldiers do you have?:";
cin >> soldiers;
return 0;
}
The problem is that when I compile it the progam only lets me insert the first 2 variables and then it shows the rest of the questions (after compile):
Name of kingdom: steve
were you conquered (true/false): false
How many gold do you have?:
How many food do you have?:
How many citizens do you have?:
How many soldiers do you have?:
Entering string "true" to the bool variable does not work. You should enter 1 or 0. Your "true" cannot be "consumed", so it's left in the buffer. Next, you're trying to read int value, so "true" also does not match. And so on... until the end of the program.
That's how I would do that:
#include <string>
#include <iostream>
#include <errno.h>
#include <stdlib.h>
using namespace std;
void askForString(string aPrompt, string &aValue) {
cout << aPrompt << " ";
cin >> aValue;
}
void askForBool(string aPrompt, bool &aValue) {
string tString;
while (1) {
cout << aPrompt << " ";
cin >> tString;
if (tString == "true") {
aValue = true;
break;
} else if (tString == "false") {
aValue = false;
break;
} else {
cout << "Repeat, please?" << endl;
}
}
}
void askForInt(string aPrompt, int &aValue) {
string tString;
char *endptr;
while (1) {
cout << aPrompt << " ";
cin >> tString;
errno = 0;
aValue = strtol(tString.c_str(), &endptr, 10);
if (errno || tString.c_str() == endptr || (endptr != NULL && *endptr != 0)) {
cout << "Repeat, please?" << endl;
} else {
break;
}
}
}
int main(void) {
string strKingdom;
bool conquered_me;
int gold;
int food;
int citizens;
int soldiers;
askForString("Name of kingdom:", strKingdom);
askForBool("were you conquered (true/false):", conquered_me);
askForInt("How many gold do you have?:", gold);
askForInt("How many food do you have?:", food);
askForInt("How many citizens do you have?:", citizens);
askForInt("How many soldiers do you have?:", soldiers);
cout << "Kingdom: " << strKingdom << endl;
cout << "Conquered: " << (conquered_me ? "true" : "false") << endl;
cout << "Gold: " << gold << endl;
cout << "Food: " << food << endl;
cout << "Citizens: " << citizens << endl;
cout << "Soldiers: " << soldiers << endl;
return 0;
}
Bring them all into strings, and convert as needed.
For some reason (probably compatibility with older code) iostreams default to converting true to 1 and false to 0 during I/O.
That's only the default though--there's a manipulator named boolalpha that will set the stream to use true and false (or localized equivalents) instead.
So, code like:
std::cout << 1 == 0; // produces `0`
std::cout << boolalpha << 1 == 0; // produces `false`
This also works for input, so you can change your code to something like this:
cin >> boolalpha >> conquered_me;
...and it should work as expected (and in: it should accept inputs of false or true, and produce values of false and true from them, and if it doesn't that's bug in the standard library).
None of your read commands check for error. ALL of them should be written as something like:
while (!(std::cin >> strKingdom)) {
std::cerr << 'Bad input' << std::endl;
std::cin.clear(); // clear the error
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // ignore the rest of the line
// output the same prompt again?
}
To make this easier, you might want to write a helper function:
template<typename T> void get_input(const char *prompt, T &result) {
std::cout << prompt << std::endl;
while (!(std::cin >> result)) {
std::cerr << 'Bad input' << std::endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << prompt << std::endl; } }
You can then specialize that for bool types to read true/false properly...
This line:
cin >> conquered_me;
Should be like this:
cin >> boolalpha >> conquered_me;
Otherwise the input expects either a "0" or a "1".
By using boolalpha your input can be "true" or "false.
You need to employ std::getline and std::string to read the various values. (You can then use functions like atoi to parse them.) Here is your code sample using the std::getline function.
#include <iostream>
#include <string>
#include <cstdlib>
int main(){
std::string strKingdom = "";
bool conquered_me;//see if was conquered, was going to use this on other program and true = game over.
int gold;
int food;
int citizens;
int soldiers;
std::string tString = ""; // Used to read and subsequently parse the string.
std::cout << std::endl <<"Name of kingdom: ";
std::getline(std::cin,strKingdom);
std::cout << std::endl << "were you conquered (true/false): ";
std::getline(std::cin,tString);
conquered_me = (tString == "true");
std::cout << std::endl << "How many gold do you have?:";
std::getline(std::cin,tString);
gold = std::atoi(tString.c_str());
std::cout << std::endl << "How many food do you have?:";
std::getline(std::cin,tString);
food = std::atoi(tString.c_str());
std::cout << std::endl << "How many citizens do you have?:";
std::getline(std::cin,tString);
citizens = std::atoi(tString.c_str());
std::cout << std::endl << "How many soldiers do you have?:";
std::getline(std::cin,tString);
soldiers = std::atoi(tString.c_str());
return 0;
}
In case of an invalid input, I want extract the invalid input from cin and store it in a variable that fits. How can I do that?
#include<iostream>
using namespace std;
int main(){
int number;
cout << "Enter a number: " << endl;
cin >> number;
if(cin.fail()){
cout << "Error!" << endl;
//HOW CAN I STORE THE INVALID INPUT WHICH IS STORED IN cin INTO A STRING?
}
return 0;
}
When you detect that failbit is set, reset it, and use std::getline to read entire line of invalid input into std::string from std::cin:
#include <iostream>
#include <string>
int main()
{
int number;
while(true)
{
std::cout << "Enter a number (0 to exit): " << std::endl;
std::cin >> number;
if(std::cin.fail())
{
std::string error_data;
std::cin.clear(std::cin.rdstate() & ~std::ios::failbit);
std::getline(std::cin, error_data);
std::cout << "You didn't enter a number - you've entered: " << error_data << std::endl;
}
else
{
std::cout << "Number is: " << number << std::endl;
if(number == 0)
{
break;
}
}
}
return 0;
}
I am a beginning c++ student and am attempting to write a program that takes a word in a file and indexes it, listing each word only once and displaying the line numbers of every time that word appears. I have tried using a map but i found it impossible to get the line numbers for the words. Instead, I am using a vector of structs that has an integer vector and a string for each word. I am trying to read each word, place it into a stringstream, then output it into the string in the struct. Then I take the line number and push_back it into the vector in the struct. then I save everything to the vector of the struct and try to print out each word associated with the line number vector. I am getting nowhere and would like some help. Itd be much appreciated! Here is my source code:
#include <iostream>
#include <string>
#include <fstream>
#include <map>
#include <sstream>
#include <vector>
using namespace std;
struct words {
vector<int> lineNumbers;
string word;
};
int main() {
ifstream inFile, testStream;
ofstream outFile;
string temp, choice, inFileName, outFileName, word, trash, word2, tempString;
int idx = 0, count = 0, idxTwo = 0;
bool outputOpened = false;
//map <string,int> wordList;
/map <string,int>::iterator wordIt;
stringstream myStream(ios_base::in| ios_base::out);
vector<words> myIndex;
words data;
for (;;) {
cout << "Options: "<< endl << "1. Index" << endl << "2. Quit" << endl
<< "Please enter an option: ";
getline(cin, temp);
//cin >> temp;
//cin.ignore(8192, '\n');
choice.resize(temp.length());
transform(temp.begin(), temp.end(), choice.begin(), ::toupper);
if (choice.compare("INDEX") == 0 || choice.compare("1") == 0) {
do {
inFileName.clear();
cout << "Index Program" << endl
<< "==============" << endl << endl;
cout << "Input file name: ";
getline(cin, inFileName);
inFile.open(inFileName.c_str());
if(inFile.fail()) {
cout << "Can't open file" << endl;
if(inFile.bad()) {
cout << "Bad" << endl;
}
inFile.clear();
}
}
while (!inFile.is_open());
do {
cout << "Output file name: ";
getline( cin, outFileName);
testStream.clear();
testStream.open(outFileName.c_str());
if(testStream.good()) {
cout << "That file already exists, try again" << endl;
testStream.clear();
testStream.close();
}
else {
testStream.clear();
testStream.close();
outFile.open(outFileName.c_str());
if (outFile.good()) {
outputOpened = true;
}
}
}
while (!outputOpened);
while (getline(inFile, trash)){
count++;
myStream << trash;
//myStream >> tempString;
while(myStream >> data.word) {
data.lineNumbers.push_back(count);
myIndex.push_back(data);
}
}
for (idx = 0; idx < myIndex.size(); idx++) {
outFile << "Word: "<< " "<< myIndex[idx].word << ", ";
for (idxTwo = 0; idxTwo < myIndex[idx].lineNumbers.size(); idxTwo++) {
outFile << "Found on lines " << " " << myIndex[idx].lineNumbers[idxTwo];
}
}
inFile.close();
outFile.close();
}
else if (choice.compare("QUIT") == 0 || choice.compare("2") == 0) {
return 0;
}
else {
cout << temp << " is an unrecognized option, please try again" << endl;
}
}
return 0;
}
Your problem seems to be that you are always appending each word to the vector<words>.
What you probably want, is a map<string, vector<int>>. Use .insert to insert words in to the set, if it already exists then just append the current line number to the value.
For this part of your program:
while (getline(inFile, trash)){
count++;
myStream << trash;
//myStream >> tempString;
while(myStream >> data.word) {
// 2.
// data.lineNumbers.clear();
data.lineNumbers.push_back(count);
myIndex.push_back(data);
}
// 1. add:
// myStream.clear();
}
You are using a global myStream. But the state of this myStream will be in a bad state after processing each line, as it ran out of data. The state mush be cleared for it to work again.
The data is also global, which make the line number for every word to be saved in data.lineNumber, not only the line number of the current word. You may want to clear it at each run.
Here are some issues:
Add myStream.clear(); after the while(myStream >> data.word) loop.
Add "\n" to the end of the following line to print on a new line:
outFile << "Found on lines " << " " << myIndex[idx].lineNumbers[idxTwo]<<"\n";
Also, the following nested loop will not give you correct results. It will grow with line numbers and keep printing "Found on lines":
for (idx = 0; idx < myIndex.size(); idx++) {
outFile << "Word: "<< " "<< myIndex[idx].word << ", ";
for (idxTwo = 0; idxTwo < myIndex[idx].lineNumbers.size(); idxTwo++) {
outFile << "Found on lines " << " " << myIndex[idx].lineNumbers[idxTwo]<<"\n";
}