user2993456
user2993456

Reputation:

cin unintentionally skipping user input

I am trying to write a loop that validates user input, and then repeats if the input is bad. The input must be either a binary number (as a string) or a decimal number (as an int). I have seperate functions to validate this input, but they are not causing any trouble.

The problem arises when I select 1 or 2, and then willingly enter an invalid binary or decimal number. At this point, the do-while loop repeats successfully. The program prints another request for user input to cout, But when it comes time for the user to enter input, the program thinks that there is input in the console before I even enter anything. I believe this is a problem with whitespace/control characters in the buffer, but I am not sure how to fix it. I have tried using std::cin >> std::ws to clear any straggling white space, but no luck.

#include <iostream>
#include <string>
#include <limits>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

using std::cout;
using std::cin;
using std::endl;
using std::numeric_limits;
using std::max;
using std::streamsize;
using std::string;



//int toDecimal;

//true is is binary
bool validateBinary(const string &binaryNumber){
    for(int i = 0; i < binaryNumber.length(); i++){
        if((binaryNumber[i] != 1) && (binaryNumber[i] != 0)){
            return false;
        }
    }
    return true;
}
//true if is decimal
bool validateDecimal(){
    return cin;
}

int main() {
    int conversionType = 0; //we initialize conversionType to a default value of 0 to ensure the copiler it will always have a value
    bool isBinary = false;
    bool isDecimal = false;
    string binaryNumberInput;
    int decimalNumberInput;

    do {
        if(conversionType == 0){
        cout << "Enter 1 to convert binary to decimal," << endl;
        cout << "2 to convert decimal to binary, " << endl;
        cout << "or 3 to exit the program: ";
        std::cin >> std::ws; //to clear any whitespace fron cin
        cin >> conversionType; //upon a second iteration, this value is read in before a user input is given
        }

        if(!cin || (conversionType != 1 && conversionType != 2)){
            cout << "Incorrect input." <<  endl;
            cin.clear(); //clear the fail bit
            cin.ignore(numeric_limits<streamsize>::max(), '\n'); //used to ignore not-numeric input
        }

        cout << "You have selected option " << conversionType << "." << endl;

        if(conversionType == 1){
            cout << "Please enter a binary number: ";
            cin >> binaryNumberInput;
            isBinary = validateBinary(binaryNumberInput);
            if(!isBinary){
                cout << "The numbered you entered is not a binary number!" << endl;
                conversionType = 0;
            }
        }

        if(conversionType == 2){
            cout << "Please enter a decimal number: ";
            cin >> decimalNumberInput;
            isDecimal = validateDecimal(); //true if succeeded, meaning is a number
            if(!isDecimal){
                cout << "The numbered you entered is not a decimal number!" << endl;
                conversionType = 0;
            }
        }
    }
    while((conversionType != 1 && conversionType != 2) || (isBinary == isDecimal));


    return 0;

}

Upvotes: 0

Views: 77

Answers (1)

user657267
user657267

Reputation: 20990

Rather than debug your current program you might want to consider using the standard library to simply things

#include <iostream>
#include <string>
#include <bitset>
#include <climits>
#include <limits>

template<typename T>
void get(T& value)
{
  while (!(std::cin >> value)) {
    std::cout << "Invalid input\n";
    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
  }
}

int main()
{
  std::cout << "Enter 1 to convert binary to decimal,\n" <<
               "2 to convert decimal to binary\n";

  int option;

  if (std::cin >> option) {
    switch (option) {
      case 1: {
        std::bitset<CHAR_BIT * sizeof(unsigned long long)> bits;
        get(bits); 
        std::cout << bits.to_ullong()  << '\n';
        break;
      }

      case 2: {
        unsigned long long i;
        get(i);
        std::cout << std::bitset<CHAR_BIT * sizeof i>(i) << '\n';
        break;
      }
    }
  }
}

If you want this to loop you should be able to add it back in again easily enough.

Upvotes: 1

Related Questions