I would like to make the user input a center number of character, e.g. 10, however, the user might input more than 10.
for(int i = 0 ; i< 10 ; i++)
cin>>x;
The extra character could make my code crash since I will ask for input later.
How can I clear the input at this moment when the user input more than 10?
Thanks so much!
std::cin.clear();
std::cin.ignore(std::numeric_limits<streamsize>::max(),'\n');
This should reset the failbit and ignore the bad input.
By the way, to avoid duplicating all that code every time, I once wrote a little template function to do that work:
template<typename InType> void AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString, InType & Result)
{
do
{
Os<<Prompt.c_str();
if(Is.fail())
{
Is.clear();
Is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
Is>>Result;
if(Is.fail())
Os<<FailString.c_str();
} while(Is.fail());
}
template<typename InType> InType AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString)
{
InType temp;
AcquireInput(Os,Is,Prompt,FailString,temp);
return temp;
}
The first overload may be preferred if you want to avoid copying, the second may be more convenient for builtin types.
Usage examples:
//1st overload
int AnInteger;
AcquireInput(cout,cin,"Please insert an integer: ","Invalid value.\n",AnInteger);
//2nd overload (more convenient, in this case)
int AnInteger=AcquireInput(cout,cin, "Please insert an integer: ","Invalid value.\n");
cin goes into an error mode and stops doing anything if the user gives invalid input. You need to add a check for invalid input and a loop to retry.
for(int i = 0 ; i< 10 ; i++)
while ( ( cin >> x ).rdstate() == ios::failbit ) {
cin.clear();
cin.ignore( numeric_traits<streamsize>::max(), '\n' );
}
It's a lot of work, but you need to define some kind of policy for ignoring invalid input. There are other choices; this just ignores the remainder of the line.
This shows how to clear the entire buffer on an error.
from: http://support.microsoft.com/kb/132422
/* No special compile options needed. */
#include <iostream.h>
int ClearError(istream& isIn) // Clears istream object
{
streambuf* sbpThis;
char szTempBuf[20];
int nCount, nRet = isIn.rdstate();
if (nRet) // Any errors?
{
isIn.clear(); // Clear error flags
sbpThis = isIn.rdbuf(); // Get streambuf pointer
nCount = sbpThis->in_avail(); // Number of characters in buffer
while (nCount) // Extract them to szTempBuf
{
if (nCount > 20)
{
sbpThis->sgetn(szTempBuf, 20);
nCount -= 20;
}
else
{
sbpThis->sgetn(szTempBuf, nCount);
nCount = 0;
}
}
}
return nRet;
}
void main()
{
int n = 0, nState;
while (n <= 100)
{
cout << "Please enter an integer greater than 100.\n";
cin >> n;
nState = ClearError(cin); // Clears any errors in cin
}
}
Related
sorry for such a stupid question but I couldn't find any obvious answer.
I need to read from stdin first an int n with the size of an array, and then integer values from a string in the format "1 2 3 4 5 6" with n elements.
If I knew the number of parameters at compile time I could use something like a scanf (or the safe alternatives) with a format string like "%d %d %d %d %d %d", but here I will only know that value at run time.
What would be the best way to do this in C++? Performance is important but more than that safety.
How should I read a format string of variable length in C++ from stdin?
You should not attempt to do such thing. Only ever use constant format strings.
I need to read from stdin first an int n with the size of an array, and then integer values
What would be the best way to do this in C++?
Read one value at a time. Repeat using a loop.
Here's a function that does what errorika describes:
const int SIZE = //as much of your memory as you'd like the user to have access to
***caller function must include this:
//allocate a string to hold some data;
char* buffer = NULL;
buffer = malloc (SIZE * sizeof(char));
if (buffer == NULL) {
printf("malloc error terminating\n");
return;
}
***
void getEntry(char* buffer) {
int count = 0;
int maxlen = SIZE - 1;
char a = '0';
for (int i = 0; i < SIZE; i++) {
buffer[i] = '0';
}
while (a != '\n' && count < maxlen) {
a = fgetc(stdin);
buffer[count] = a;
count++;
}
if (a == '\n') {
buffer[count - 1] = '\0';
}
else {
buffer[count] = '\0';
do {
a = fgetc(stdin);
} while (a != '\n');
}
}
This is all basic C code but user entry is evil. Here is what I've come up with for more C++ idiomatic user input functions (query is just the message string you pass in):
template<typename T>
void getInput(const std::string query, T& entry) {
std::string input;
std::cout << query << std::endl;
getline(std::cin, input);
std::stringstream buffer{input};
buffer >> entry;
}
OR
template<typename T>
void getInput2(std::string query, T& entry) {
bool validInput = false;
while (validInput == false)
{
validInput = true;
std::cout << query << std::endl;
std::cin >> entry;
if (std::cin.fail()) {
validInput = false;
std::cout << "Unacceptable entry\n" << std::endl;
}
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
Good day,
I am trying to read data from a file into an array of objects. I can't seem to find how to tackle the space delimiter. Kindly help me.
The class is called Rational and it has two properties: num and denom.
File data: 1/2 -1/3 3/10 4/5 6/18
So far I have done this:
int operator>>(ifstream& fin, rational r[]) {
fin.open("filedata.txt", ios::in);
if (fin)
{
for (int i = 0; i < 5; i++)
{
fin >> r[i];
}
}
else
{
cout << "\nData file cannot be found!" << endl;
}
}
ifstream& operator>>(ifstream& in, rational& r)
{
int num, denom;
char slash;
in >> num >> slash >> denom;
r.set(num,denom);
return in;
}
Thanks in advance.
The function operator>>(ifstream& in, rational& r) should work as posted although I would change it to
std::istream& operator>>(std::istream& in, rational& r) { ... }
However, the first function is not right. You are not returning anything from the function even though its return type is int. You can change it to:
int operator>>(ifstream& fin, rational r[])
{
int count = 0;
fin.open("filedata.txt", ios::in);
if (fin)
{
for ( ; count < 5; ++count)
{
// If unable to read, break out of the loop.
if ( !(fin >> r[count] )
{
break;
}
}
}
else
{
cout << "\nData file cannot be found!" << endl;
}
return count;
}
Having said that, I think you can improve that function a bit.
Open the file in the calling function, main maybe, and pass the std::ifstream object to it.
Instead of passing it an array, pass it a std::vector. Then, you don't have worry about the number of entries in the file. You read whatever you can find in the file.
Change the return type to be std::istream& so you can chain the calls if necessary.
std::istream& operator>>(std::istream& in, std::vector<rational>& v)
{
rational r;
while ( in >> r )
{
v.push_back(r);
}
return in;
}
In main (or whichever is the higher level function), use:
std::vector<rational> v;
std::ifstream fin("filedata.txt);
if ( !fin )
{
// Deal with error.
}
else
{
fin >> v;
}
// Use v as you see fit.
I am working on a huge integer problem where I have to create a HugeInteger class where the digits are to be stored in a string object instead of an array of unsigned shorts of a fixed (static) size. I am stuck on how to implement this. When I run the program, I input values for my HugeInteger objects but then nothing gets displayed afterwards. Would appreciate some help. Thanks in advance.
Below is my source code of what I have so far.
HugeInteger.h
#include <iostream>
#include <array>
#include <string>
class HugeInteger
{
// need to offer friendship to these 2 functions
friend std::istream & operator >> (std::istream & src, HugeInteger & value);
friend std::ostream & operator << (std::ostream & dest, const HugeInteger & value);
public:
//ctor that converts a "long long" into a HugeInteger
HugeInteger(long long value = 0LL); //0LL is constant literal value 0
// of type long long
//ctor that converts a string into a HugeInteger
HugeInteger( char *str);
//Convert a string into a HugeInteger
void input( char *str);
private:
bool negative; // will be true if number is negative
std::string hugeInt; // each digit is stored in a string object
};
//overloads the << and >> operators for the HugeInteger class
std::istream & operator >> (std::istream & src, HugeInteger & value);
std::ostream & operator << (std::ostream & dest, const HugeInteger & value);
HugeInteger.cpp
#include "HugeInteger.h"
#include <iostream>
using namespace std;
// ctor converts a long long into a HugeInteger
HugeInteger::HugeInteger(long long value)
{
// set all MaxDigit digits to zero to start
this->negative = false;
if (value < 0LL){ // 0LL is constant literal 0 of type long long
this->negative = true;
value = -value; // make the value positive
}
unsigned int i = 0;
for (; i < hugeInt.size(); i++)
{
this->hugeInt[i] = '0';
}
this->hugeInt[i] = '\0';
// convert individual digits of input value into a HugeInteger
for (unsigned int j = hugeInt.size() - 1; j >= 0 && value != 0LL; j--)
{
short result = value % 10;
char c = (char)result;
this->hugeInt[j] = c;
value /= 10;
}
// test to make sure that HugeInteger was able to contain value
if (value != 0LL){
*this = 0LL; // set to -0, to signal overflow
this->negative = true; // Possibly should increase value assigned
} // to MaxDigit to fix this problem.
}
// converts string into a HugeInteger object
HugeInteger::HugeInteger(char *str)
{
this->input(str); //See HugeInteger::input() method below
}
void HugeInteger::input( char *str)
{
// assume positive for now
this->negative = false;
// init. to all zeros first
unsigned int i = 0;
cin.getline(str, sizeof str);
cin.sync();
cin.clear();
while (i < strlen(str) - 1)
{
if (isdigit(str[i]))
{
this->hugeInt[i] = str[i];
i++;
}
}
istream & operator>>(istream & input, HugeInteger & value)
{
char inputString[1002];
input >> inputString;
value.input(inputString);
return input;
}
ostream & operator << (ostream & output, const HugeInteger & value)
{
// find first non-zero digit
unsigned int i = 0;
while (i < value.hugeInt.size()){
if (value.hugeInt[i] != '0'){
break;
}
++i;
}
// if all zeros, just output a single 0
if (i == 40)
{
cout << '0';
return output;
}
// check if we need to ouput a negative sign
if (value.negative){
cout << '-';
}
// output remaining digits
for (; i < value.hugeInt.size(); i++)
{
cout << value.hugeInt[i];
}
return output;
}
MainProg.cpp
#include "HugeInteger.h" // include definiton of class HugeInteger
using namespace std;
int main()
{
HugeInteger A, B, C, D;
// input value for A & B
cout << "****** Test << & >> operators ******\n\n";
cout << "Input values for A and B: ";
cin >> A >> B;
cout << "\nA = " << A << "\nB = " << B;
system("pause");
return 0;
} // end main
There are several issues with your code, however the most glaring are your input functions.
First, why does HugeInteger::input need to know how the input was retrieved? There is no need for cin or any I/O -- it's job is to solely take a char * pointer, and loop through it creating the hugeInt string.
Therefore, the lines below should be removed:
cin.getline(str, sizeof str);
cin.sync();
cin.clear();
The next issue is the actual loop. There are several things wrong with it.
First, you should be incrementing i, regardless if the character is a digit or not. Otherwise, you will end up in an infinite loop if the character is not a digit.
Second, when you are building the hugeInt string, you should be concatentating the character onto the string. Your current code leads to undefined behavior since you are accessing hugeInt[i], and hugeInt is an empty string, so there is no i entry.
So the changes there would be this:
while (i < strlen(str) - 1)
{
if (isdigit(str[i]))
this->hugeInt += str[i];
i++;
}
Now, a better implementation would be to have input take a std::string, not a char*. Now, the total function would be rewritten thusly:
void HugeInteger::input(const std::string& str)
{
// assume positive for now
this->negative = false;
// init. to all zeros first
unsigned int i = 0;
this->hugeInt.clear();
while (i < str.size())
{
if (isdigit(str[i]))
this->hugeInt += str[i];
i++;
}
}
The last issue is your operator >>. There is no need to limit yourself to 1002 characters. Just input into a std::string.
istream & operator>>(istream & input, HugeInteger & value)
{
string inputString;
input >> inputString;
value.input(inputString);
return input;
}
After these changes, the sample runs correctly: http://ideone.com/F47TEV
Edit:
An alternate way of extracting the digits and appending onto a string using the STL algorithm functions would be as follows:
void HugeInteger::input(std::string str)
{
// assume positive for now
this->negative = false;
str.erase(std::remove_if(str.begin(), str.end(), [](char ch)
{ return !isdigit(ch);}), str.end());
hugeInt = str;
}
The std::remove_if is stable, so the relative order of the digits will not be changed. Also note that we pass by value, as this gives the compiler (if it's C++ 11) a good chance to optimize the copy that is passed (as opposed to making your own copy inside the function).
Your current code leads to undefined behavior since you are accessing hugeInt[i], and hugeInt is an empty string, so there is no i entry.
Just to add to this, the lines
for (; i < hugeInt.size(); i++)
and
for (unsigned int j = hugeInt.size() - 1; j >= 0 && value != 0LL; j--)
will never initially execute as hugeInt.size() will be 0 and the for loop condition will never be satisfied
I'm new to C++ and working on a simple guessing game where you get 5 tries to guess a number between 1 and 100.
I'm having issues dealing with user inputs.
I've made it so that the program only accepts numbers between 1 and 100, and it ignores characters without crashing. The problem is that when I type in gibberish like 34fa1e8, the loop will run three times, using 34 the first time, 1 the second time, and 8 the last time, instead of ignoring the input like I want it to.
The code im using is here:
int check_guess() {
int guess;
do {
cin >> guess;
if (cin.fail()) {
cin.clear();
cin.ignore();
}
} while (guess < 1 || guess > 100);
return guess;
}
How can I make the program dismiss inputs like these instead of accepting them separately?
You could use getline and stol.
I've given an answer like this before; an explanation can be found here.
You can even extended the solution to check for the specified range:
template <int min, int max>
class num_get_range : public std::num_get<char>
{
public:
iter_type do_get( iter_type it, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, long& v) const
{
auto& ctype = std::use_facet<std::ctype<char>>(str.getloc());
it = std::num_get<char>::do_get(it, end, str, err, v);
if (it != end && !(err & std::ios_base::failbit)
&& ctype.is(ctype.alpha, *it))
err |= std::ios_base::failbit;
else if (!(min <= v && v <= max))
err |= std::ios_base::failbit;
return it;
}
};
Now you can imbue the stream with the new locale and you need to restructure your loop to discard valid input. For example:
std::locale original_locale(std::cin.getloc());
std::cin.imbue(std::locale(original_locale, new num_get_range<1, 100>));
int check_guess()
{
int guess;
while (!(std::cin >> guess))
{
std::cin.clear();
std::cin.igore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
Use ifstream::getline to store the input in a char array. Then convert it to an integer using a function like this:
int convertToInteger(char const *s){
if ( s == NULL || *s == '\0'){
return 0;
}
int result = 0, digit = 1000;
while((*s) && (digit > 0)){
if ( *s >= '0' && *s <= '9' ){
result += digit * (*s - '0');
}else{
return 0;
}
++s;
digit /= 10;
}
return result;
}
The reason it works is because it will return 0 in case of failure and that's something your loop's condition will not accept. You also don't have to worry about negative numbers since your loop won't accept them anyways.
I get "Run-Time Check Failure #2 - Stack around the variable 'id' was corrupted." on while condition . I've no idea! what causes this err?
void Term::set_id()
{
char id[Term::ID_LENGTH];
do
{
cout << "\n\nEnter the term id(like 90911): ";
cin >> id;
}while(valid_id(id) != true);
}
bool Term::valid_id(char *id)
{
//counting how many chars id has got:
int n=0;
for(char* str=id; *(str+n)!=0; n++);
if(n!=Term::ID_LENGTH)
return false;
//checking that id consist of digits only
int i=0;
for( char* str=id; (*(str+i)>=48 && *(str+i)<=57) && i<Term::ID_LENGTH; i++);
if(i<Term::ID_LENGTH)
return false;
int fy= (*(id) - 48) * 10 + (*(id+1) - 48);//former year
int ly= (*(id+2) - 48) * 10 + (*(id+3) - 48);//latter year
int t= *(id+4) - 48;//term number
if(ly - fy != 1)//any difference other than 1
return false;
if(!(t==1 || t==2 || t==0))//t==0 is for summer term
return false;
return true;
}
This code looks like a simple array overrun. std::cin >> str for str being a char array or a pointer to char is the C++ version of C's gets() if you don't set up the stream's width() to limit the number of characters to be read:
char id[Term::ID_LENGTH];
std::cin.width(Term::ID_LENGTH); // <-- without this you are prone to array overrun!
if (std::cin >> id) {
// deal with a successful read
}
You should consider using std::string for the input of character strings:
std::string id;
if (std::cin >> id) {
// deal with a successful read
}
The source of the problem was Term::ID_LENGTH forgotten to count the '\0'.