Thread: invalid input

  1. #1
    Registered User
    Join Date
    Sep 2010
    Posts
    8

    invalid input

    I'm trying to write code that will give the user an error if they type anything besides a number, dont even know where to start

  2. #2
    Just a pushpin. bernt's Avatar
    Join Date
    May 2009
    Posts
    426
    Check it out - MSDN has something to this effect on the cin reference page.
    Consider this post signed

  3. #3
    Registered User
    Join Date
    Sep 2010
    Posts
    33
    I think, though I may well be wrong, that using getline and entering the number as a string, is the most robust method. You can then validate and convert the string to another format or data type as required.

    Validating a string is something you definitely need to learn anyway.

    Alternatively, here’s a nice little routine that forces the input of a number using a do loop until you enter a predetermined number of your choice, -1 in this example.

    I found this example on 1. Keyboard Input and it is very well explained.

    But I’m not suggesting that this is how it should be done.

    Code:
    float x = 0;
    	string badChars;
    	do {
    		cout << "Enter a number (-1 = quit): ";
    		if(!(cin >> x)) {
    			cout << "The input stream broke!" << endl;
    			cin.clear();
    			cin >> badChars;
    			cout << "You typed \"" << badChars << "\" instead of a number." << endl;
    			cout << "Please try again." << endl;
    		}
    		else if(x != -1) {
    			cout << "You entered " << x << endl;
    		}
    	}
    	while(x != -1);
    	cout << "Quitting program." << endl;
    Of course it depends on your application and what you’re trying to achieve, which will be different every time. So don’t get hung up on any particular solution.
    Last edited by Michael432000; 09-18-2010 at 03:42 AM.

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    If you want some code that's ready to use, or if you wish to study an advanced sample, here is an example of how to do it safely:
    Code:
    #ifndef INPUT_20081018_H
    #define INPUT_20081018_H
    
    #include <boost/format.hpp>
    #include <iostream>
    #include <string>
    #include <sstream>
    
    namespace Stuff
    {
        namespace Input
        {
            template<typename StrT> void StreamOut(const StrT& Output) { std::wcout << Output; }
            void StreamOut(const char* Output) { std::cout << Output; }
            void StreamOut(const std::string& Output) { std::cout << Output; }
            template<typename T> void StreamOut(const boost::basic_format<T>& Output) { StreamOut(Output.str()); }
    
            template<typename StrT, typename T> bool StreamIn(StrT& Stream, T& Buffer)
            {
                std::wstring Answer;
                std::getline(Stream, Answer);
                std::wstringstream StrStream(Answer);
                void* SuccessPtr = (StrStream >> Buffer);
                return SuccessPtr != nullptr;
            }
    
            template<typename T> bool StreamIn(T& Buffer) { return StreamIn(std::wcin, Buffer); }
    
            // Read function overloads
            // Read function with no validator func
            template<typename DataT, typename StrT1>
            void ReadNoVal(DataT& Out, const StrT1& Question)
            {
                Read(Out, Question, L"Invalid input!\n", L"Invalid input!\n", [](const DataT&){ return true; });
            }
    
            template<typename DataT, typename StrT1, typename StrT2>
            void ReadNoVal(DataT& Out, const StrT1& Question, const StrT2& ErrorType)
            {
                Read(Out, Question, ErrorType, L"Invalid input!\n", [](const DataT&){ return true; });
            }
    
            template<typename DataT, typename StrT1, typename StrT2, typename StrT3>
            void ReadNoVal(DataT& Out, const StrT1& Question, const StrT2& ErrorType, const StrT3& ErrorValidation)
            {
                Read(Out, Question, ErrorType, ErrorType, [](const DataT&){ return true; });
            }
    
            // Read functions with validator function
            template<typename DataT, typename StrT1, typename Validator>
            void Read(DataT& Out, const StrT1& Question, Validator ValidatorFnc)
            {
                Read(Out, Question, L"Invalid input!\n", L"Invalid input!\n", ValidatorFnc);
            }
    
            template<typename DataT, typename StrT1, typename StrT2, typename Validator>
            void Read(DataT& Out, const StrT1& Question, const StrT2& ErrorType, Validator ValidatorFnc)
            {
                Read(Out, Question, ErrorType, L"Invalid input!\n", ValidatorFnc);
            }
    
            template<typename DataT, typename StrT1, typename StrT2, typename StrT3, typename Validator>
            void Read(DataT& Out, const StrT1& Question, const StrT2& ErrorType, const StrT3& ErrorValidation, Validator ValidatorFnc)
            {
                for (;;)
                {
                    StreamOut(Question);
                    if (!StreamIn(Out))
                    {
                        StreamOut(ErrorType);
                        continue;
                    }
                    if (ValidatorFnc(Out))
                        break;    
                    StreamOut(ErrorValidation);
                }
            }
        }
    }
    
    #endif // INPUT_20081018_H
    Basically, read a string, use string streams to convert to proper type, check if the input data is valid, then return it. If any of the steps fails, ask for the input again.

    Good luck.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    Registered User
    Join Date
    Sep 2010
    Posts
    33
    Ah, real code, that’s what I’m looking for. Really appreciate you posting this, thank you. Beautiful.

  6. #6
    Registered User
    Join Date
    Sep 2010
    Posts
    8
    Wow, thanks both of you. I actually have a thing where I won't use any code until I know everything about it, so I'll be doing a lot of research on the code you guys used =) Thanks again! These will be a great reference for me

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    You are free to ask questions in order go get a better understanding.
    Really understanding what you're using is a noble goal, I think. Praiseworthy.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #8
    Registered User
    Join Date
    Sep 2010
    Posts
    8
    Alright, I'm trying to create my own version of the code you guys made. What I want to do is when the user inputs data into the win32 console and it's invalid (a letter), the letter is completely cleared out of the console, while keeping all other data on the screen. Then I'll put the blinking I bar (position to type) back where it was origonally.

    Also #include <boost/format.hpp> is not in my library in Visual Studio 2010
    Last edited by Ji33my; 09-21-2010 at 03:26 PM.

  9. #9
    Nasal Demon Xupicor's Avatar
    Join Date
    Sep 2010
    Location
    Poland
    Posts
    179
    I don't think you can do it without using things "external" to the standard C++, like WinApi or ncurses/pdcurses. Why not just make the user repeat the input process?

  10. #10
    Registered User
    Join Date
    Sep 2010
    Posts
    8
    Elysia, your code is slightly too advanced for me at the moment, but i will definitely be looking into it in the future when i get into that type of code.

    I actually have an idea of how I want to do it. Once an error is posted, I'll develop code that will find the position of the inputed data within the console and cout spaces instead for each character in the string. That is more towards the end of my code....i'm actually struggling right now getting my program to work the way I want it. Here is the code and i'll explain what I'm trying to do

    Code:
    #include "stdafx.h"
    #include <iostream>
    using namespace std;
    
    
    void error(int p)
    {
    	char badChars;
    
    		if(!(cin >> p))
    		{
    			std::cin.ignore(std::numeric_limits<streamsize>::max(),'\n');
    			cout << "The input stream broke!" << endl;
    			cin.clear(p);
    			cin >> badChars;
    			cin.get();
    		}
    		else
    			cin >> p;
    
    
    }
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	int x = 0, b = 0, c = 0;
    
    	cout << "Enter a  (-1 = quit): ";
    	error(b);
    	cout << b;
    	cout << "Enter c (-1 = quit): ";
    	error(c);
    	cout << c;
    	
    
     	return (0);
    }


    Alright, clearly you can see what I'm trying to do. I want the possibility of invalid input computed outside my main function, and if theres no error it computes it and moves on to the next step in the main function. I'm struggling with getting this to work the way I want, not to mention the value the you type in does not transfer over to the variable in the main function which i can't figure out how to do.

    ignore the -1 = quit portion, i just want to check for invalid input and then put the value into the specified variable in my main function
    Last edited by Ji33my; 09-21-2010 at 04:01 PM.

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by Ji33my View Post
    Also #include <boost/format.hpp> is not in my library in Visual Studio 2010
    It's a dead dependency that I've forgotten to remove. You should be able to remove it without problems.
    Otherwise, it's part of boost, an open source C++ library. And usually the breeding ground for many libraries that goes into the STL.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #12
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Code:
    void error(int p)
    {
    	char badChars;
    
    		if(!(cin >> p))
    		{
    			std::cin.ignore(std::numeric_limits<streamsize>::max(),'\n');
    			cout << "The input stream broke!" << endl;
    			cin.clear(p);
    			cin >> badChars;
    			cin.get();
    		}
    		else
    			cin >> p;
    }
    You hardly see cin::clear called with an argument. That function is there to set a state for the stream, and by default, it is the good state. If you do call it with an argument, it's supposed to be a state variable. If this compiles, then I guess that means the state is based on int at some level. Anyway, that's not really pertinent knowledge for something like this.

    To fix this, lets try analyzing the flow of what you want.
    I want the possibility of invalid input computed outside my main function,
    And of course, you write error because functions calling functions are a good way of going "outside".
    and if theres no error it computes it and moves on to the next step in the main function.
    You flip flopped steps. If we break it down even more, you ask the user for some data: std::cin >> input;
    which either was an integer or not: if (cin)
    If it was an integer you can go on to the next step in main: return;
    If it was not an integer, you need to reset the stream: std::cin.clear();
    And clean up the users mistakes: std::cin.ignore(std::numeric_limits<streamsize>::m ax(),'\n');
    And get back to this step: std::cin >> input;

    Now, as you may have realized, you can't get to that last step without controlling what the program executes next. Normally the program proceeds in top down fashion:

    work;
    work;
    work;

    But you need to keep trying std::cin >> input; until the user tries something that the computer recognizes as an integer.

    You need a loop, and a way for main to receive the integer.

    Code:
    int getInteger();
    int main()
    {
       int p = getInteger();
       return 0;
    }
    int getInteger()
    {
       int p;
       std::cin >> p;
       while (!std::cin)
       {
          std::cin.clear();
          std::cout << "The input stream broke! gj" << std::endl;
          std::cin.ignore(std::numeric_limits<streamsize>::max(),'\n');
          std::cin >> p;
       }
       return p;
    }
    The difference between this and Elysia's code is night and day. Elysia's code is multipurpose, and you can impose some sort of rule through additional verification. This is for strictly C++ ints, and anything that fits in them is valid. If that is not sufficient, (and why would it be?) then there is an additional test inside the loop condition, to keep trying until you get exactly the integer you want.
    Last edited by whiteflags; 09-22-2010 at 03:30 PM.

  13. #13
    Registered User
    Join Date
    Sep 2010
    Posts
    33
    That code is too advanced for me too, at the moment, but I will keep working on it, or towards it.

    If that boost library is a dead dependency, then what about the reference to boost on line 16?

    I managed to download c++ Boost libraries, and run a little tutorial, but it was killing my already slow machine, so I uninstalled it.

    Can you copy those boost headers to somewhere else and just leave those that you want to use. A bit confusing for a beginner.

    I would at least like to get that code compiled.

  14. #14
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Ah, right. You can comment that out.
    I regularly work with boost and boost::format is a very nice library, so I added some support for it.

    I'll probably write a short tutorial on using it sometime.
    Last edited by Elysia; 09-23-2010 at 10:31 AM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  15. #15
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    That code is too advanced for me too, at the moment, but I will keep working on it, or towards it.
    I hope you are successful soon, because I only rearranged statements you wrote in your attempt, for the most part.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. IDE for C embedded advanced editing
    By Undici77 in forum Tech Board
    Replies: 32
    Last Post: 01-16-2010, 05:17 PM
  2. how do you resolve this error?
    By -EquinoX- in forum C Programming
    Replies: 32
    Last Post: 11-05-2008, 04:35 PM
  3. Post...
    By maxorator in forum C++ Programming
    Replies: 12
    Last Post: 10-11-2005, 08:39 AM
  4. Dikumud
    By maxorator in forum C++ Programming
    Replies: 1
    Last Post: 10-01-2005, 06:39 AM
  5. input files in C
    By LWisne in forum C Programming
    Replies: 4
    Last Post: 09-30-2002, 06:24 AM