Hi there, it's been awhile :$

I have just completed a small easy exercise which was to create an Account class, providing a constructor to receive the initial account balance, add some money to the initial balance and withdraw some money (providing that the amount of money to withdraw is smaller than the value in the account) It's all good but now I am having some problems in validating the input. Basically when asked to add some money onto the account if I input a char I want my program to tell me that the input is invalid and to try again, but I don't seem to be able to do it. Here is what I have so far:

header file:

//account.h
//this file is the class definition

#include <iostream>

using namespace std ;

const char pound = 156 ;

class Account

{

	public:

		//constructor

		Account( int ) ;
		
		void credit( int ) ;
		
		void debit( int ) ;
		
		int getBalance( ) ;
		
		private: 
		
		int balance ;
		
	};

function definition:

//account.cpp
//this file contains the member function definitions
#include <iostream>

using namespace std ;

#include "account.h" //include the class definition

Account::Account( int initBalance )

		{
		
			if ( initBalance < 0 )

			{

			balance = 0 ; 

			cout << "Initial balance is invalid!\n" ;

			}
		
			else 
				
			{
				
				balance = initBalance ;

				cout << "The initial balance is "<< pound << balance << endl ; 

			}
		}

void Account::credit( int funds )
		
			{
		
				balance += funds ;		

			}
			
void Account::debit( int withdraw )
			
			{
						
				if ( withdraw > balance )
			
					{
									
						cout << "Debit amount exceeded Account's balance!\n" ;
							
					}
							
				else 
			
					{
							
						balance -= withdraw ;
			
					}
					
			}
			
int Account::getBalance()
			 
			{
		
				return balance;
			
			}

main file: this is where I am attempting the validation as the comment says

//account_main.cpp
//main file

#include <iostream>

#include <cctype>

using namespace std ;

#include "account.h"

int main()

{

int addBalance ; //to pass the fund

int toDebit ; //to pass the withdraw

Account money(300) ;

cout << " You can now add some fund to your account. How much do you want to add?\n" ;

cin >> addBalance ;

/*this is where I try to validate the input but the compiler, if I enter a char or even a 3 digits number comes back with an error (I attached the screenshot)*/

if ( isalpha( addBalance ) )
	
	{
	
		cout << " Not a valid input, try again!\n " ;

		cin >> addBalance ;

	}

cin.ignore() ;

money.credit( addBalance ) ;

cout << "The new balance after the deposit is " << pound << money.getBalance() << endl ;

cout << "Now you can withdraw money. How much would you like to withdraw?\n" ;

cin >> toDebit ;

cin.ignore() ;

money.debit( toDebit ) ;

cout << "The new balance after the withdraw is " << pound << money.getBalance() << endl ;

return 0;

}

I attached the error the compiler gives me

thanks

Attachments

All of the is* functions accept an int type, but the range must either fit into an unsigned char or equal the EOF macro. In this case, you can use cin's status to determine validity:

#include <iostream>
#include <ios>
#include <limits>

int main()
{
    int amount;

    while (!(std::cin>> amount)) {
        std::cerr<<"Invalid amount. Please try again: ";
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }

    std::cout<<"Valid amount: "<< amount <<'\n';
}

It's not perfect, but robust stream I/O is surprisingly difficult.

Edited 5 Years Ago by Narue: n/a

The easiest way to validate addBalance is to get user input as a string instead of int. Then you can check each character of the string for valid digits.

isalpha() doesn't work for you because the parameter to isalpha() is a single character, not an integer.

Example:

std::string input;
cout << " You can now add some fund to your account. How much do you want to add?\n" ;
while(1)
{
   getline(cin, input);
   // check input for non-digits
   bool valid = true;
   for(size_t i = 0; i < input.size() && valid == true; i++)
   {
      if( !isdigit(input[i]))
      {
        cout << "Error\n";
        valid = false;
      }
   }
   if( valid )
      break; // exit infinite loop
}
int addBalance;
// convert from string to int
stringstream str(input);
str >> addBalance;

[edit] Didn't see Narue's solution when I posted this ^^^

Edited 5 Years Ago by Ancient Dragon: n/a

The easiest way to validate addBalance is to get user input as a string instead of int.

That's only easy on the surface. Sure, you can check that every character is a digit, but that still doesn't guarantee a successful conversion to int. If you're going to defer to a library for the actual conversion, assuming you select a library that isn't stupid, a more robust validation will be done internally anyway.

In your code, stringstream already does this, so the manual validation prior to using stringstream is both redundant and incomplete.

You are of course right if all you want to find out if there were any non-digit characters entered and not interested in what the characters actually were.

hi there,
thanks. Following your advice here is what I added:

...
Account money(300) ;

cout << " You can now add some fund to your account. How much do you want to add?\n" ;

while (!( cin >> addBalance ) )
	
	{
	
		cout << " Not a valid input, try again!\n " ;

		cin.clear();

		cin.ignore(INT_MAX, '\n');
		
	}

cin.ignore() ;
...

Just for me to understand it correctly:

with the above code I am testing the input as it comes in. WIth

cin.clear();

what do I exactly achieve?

The

cin.ignore(INT_MAX, '\n');

I read is equivalent to what you Narue used

std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

. I used the other one because it somehow seems easier. I believe what it does is to discard the input up to the maximum int input, is it correct?
Then the libraries to include:

#include <limits>

handles this limit business, but what about

#include <ios>

?

One more question: when we say

while (!( cin >> addBalance ) )

I suppose we validate only the first character, so If I input something like 4a, it will accept it as valid woudn't it?
thanks

what do I exactly achieve?

The clear member function clears the error state, which is set when cin encounters an unexpected character. If you don't clear it, you won't be able to read anymore characters from the stream.

I read is equivalent to what you Narue used

It's only equivalent if the implementation defines streamsize as int:

typedef int streamsize;

But any assumption that depends on an implementation decision is not portable. Your way is unlikely to cause a problem, but it's not strictly correct in that streamsize could be defined as a larger type and the contents of the stream could exceed the maximum size of an int, in which case the call to ignore wouldn't discard the contents of the streambuf.

I believe what it does is to discard the input up to the maximum int input, is it correct?

Up to a count of the first argument, or until a character matching the second argument is found. The equivalent loop (greatly simplified) is as follows:

int n = INT_MAX;
char c;

while (--n >= 0 && cin.get(c) && c != '\n')
    ;

what about #include <ios>?

<ios> is where std::streamsize is defined.

I suppose we validate only the first character, so If I input something like 4a, it will accept it as valid woudn't it?

It'll read and validate until whitespace or the conversion fails. So yes, if you input "4a", it will accept 4 and leave "a" in the stream. That's one of the drawbacks of this particular approach (which is solved by using getline and stringstream). Likewise, if you input "12345a", 12345 will be accepted as valid and "a" will be left in the stream.

I note you have put

using namespace std;

at the top of your header file. This is considered bad form; anyone who ever includes a header file with this at the top of it will have their namespace polluted with no warning whatsoever. As an aside, it looks like you don't even use anything in the std namespace in your header file.

Edited 5 Years Ago by Moschops: n/a

thanks for the clarifications Narue.

I note you have put

using namespace std;

I noticed you guys on this forum don't use

using namespace std;

but I thought it was more a matter of style other than anything else, what do you mean exactly by

will have their namespace polluted with no warning whatsoever

? what type of warnings? I always thought that it was some kind of shorthand, allowing us to get the rid of the

std::

anytime we want to use cout, cin, endl, therefore I believe I use, maybe partially I am not sure, what's in the std namespace any time I cout something, isn't it the case?

The standard namespace contains a vast number of objects. Really lots and lots. Some of them are named things that you really might use yourself for something else; names like "min", "max" or "count" for example.

If you have "using namespace std" at the top of a header file, anyone who ever includes that header file is suddenly including the entire std namespace. If they already had objects with names that are in the std namespace, they are now at risk of namespace collision. If they are lucky, this will cause a compilation error and they can try to fix it. If they are unlucky, there will be no compilation error and suddenly they are using objects and functions they never meant to, and they don't even know.

Here is a thread on stackoverflow that explains it quite well:

http://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-a-bad-practice-in-c

It's not so bad in files that won't be #included, but I should be able to include a header file with no fear that it will utterly trash everything. If a company provides a commercial library and a header file to go with it, and that header file pollutes my namespace and forces me to rewrite either my code or their header file, I would be very upset indeed.

I note that you repeated "using namespace std" in your two cpp files as well, even though both them include the header file so both of them already had it. That suggests to me that this is some kind of reflex action you've been taught (i.e. I suspect that at some point someone said "always put this at the top of every file, don't ask why, just do it").

The point of namespaces is to prevent collisions; if you simply bring in an entire namespace on a global scale, you've wrecked the point of them.

Many people do simply use std:: on the front of things. Some people pick out the ones they want to use and declare them with

using std::cout

, for example.

Some people do put in a using namespace std, but they're careful to do it in a small scope; either just in their cpp file, or just within the local sub-scope where they need it, like this:

if (x)
{
  using namespace std;
  cout << x;
}

// No longer in scope, have to use std::
std::cout << x;

using std::cout;
cout << x;

// Still have to use std:: on everything else
std::cin >> x;

Whatever you choose, please choose not to put using namespace std in your global header file scope; anyone who ever has to include one will thank you (for example, in this case if you were part of a team writing a payroll programme and you were writing the account object definition that everyone else would use, they would all include your header file and suddenly find that they've got the entire std namespace everywhere).

I hope I haven't come across as too preachy. Some would argue that this is just a style question, but I contend that I should be able to include a header file to use a new object type and not worry that just including it will break all my code.

anytime we want to use cout, cin, endl, therefore I believe I use, maybe partially I am not sure, what's in the std namespace any time I cout something, isn't it the case?

You didn't use any of those in your header file, but you still have a using namespace std there.

Edited 5 Years Ago by Moschops: n/a

Comments
Good post.

Hi ya, I know what you mean. when I was writing that little program I really didn't really noticed I included the namespace everywhere, so yes, I think you're right when you say that it was more like a "reflex action", but for me it has been always a matter of convenience in a way (it saves me typing std::). With hindsight, I now realized that yes having namespace in 3 files was surely not necessary at all because I had it into the .h file, so as a consequence of including the .h files in my cpp files they had it already, as you pointed out. aLSO from what I have read on the net (but I might be wrong) it looks like people tend to use the namespace in connection with global variables which I thought were something to be avoided and considered as poor style (I am not being judgmental here but this is what I was being taught and what I experienced myself).

I think it might take me forever to get the rid of that infamous namespace at the top of my programs though, will try to do it gradually, but thanks for your advice

As you will have noticed, the vast, vast majority of your time spent "coding" had nothing whatsoever to do with pressing keys on a keyboard, and everything to do with thinking about the problem you were trying to solve, and working out where you had gone wrong in your attempts to solve it. Saving yourself a few seconds by not typing std:: is really such a minor issue. Phenomenally small.

I noticed you guys on this forum don't use

using namespace std;

but I thought it was more a matter of style other than anything else...

You will notice if you actually look at this forum that we DO use using namespace std; . Many of us don't necessarily subscribe to the idea Moschops set forth here. Note he only has a few posts here and therefore speaks for himself, not the forum as a whole.

This is not to say his idea is incorrect. Only that it is not a forum wide policy.

This question has already been answered. Start a new discussion instead.