Member Avatar for xfactornos

I have been writing my program and everything works like it should unless the user inserts a character then the whole thing blows up... how can I fix this.

Is there something I can add to block characters from being added? any help would be appreciated!

here is my code:

#include <iostream>
using namespace std;

int main()
{
	// Declaring Variables
	int numscores = 0;
	double average = 0.0;
	double total = 0.0;
errorcheck1:

	// Ask for user input: How many tests to average
	cout << "Please enter how many test scores you would like to average: ";
	cin >> numscores;

	// Check to make sure number of scores is greater then 0 but less then 101
	if (numscores <= 0 || numscores > 100)
	{
		cout << "You must enter a number greater then 0 but less then 101!" << endl;
		cout << endl;
		goto errorcheck1;
	}
	// Getting the values for the number of tests
	// Start of loop
	double scores[100] = {0};
	for (int x = 1; x <= numscores; x++)
	{
		cout << "Enter test score #" << x << ": ";
		cin >> scores[x];
		if (scores[x] < 0 || scores[x] > 100)
		{
			cout << "==============================================" << endl;
			cout << "Error: Please enter a value between 0 and 100. " << endl;
			cout << "==============================================" << endl;
			x = x - 1;
		}
	} // End of loop
	// This is the output section
	cout << "=======================================" <<endl;
	cout << "Total number of test scores: " << numscores << endl;
	// Add all of the scores and call it total
	for (int y = 0; y <= numscores; y++)
	{
		total = total + scores[y];
	}
	// End loop
	// Below I will average the scores then display them
	average = total / numscores;
	cout << "Average of all test scores: " << average << endl;
	//End
	// Needed for some compilers like mine
	return 0;
}

Ah, young grasshopper, you have advanced to the next level: you have recognized the need for better input validation.

It might be worth it to make yourself a little function that reads and returns a validated number.

Member Avatar for xfactornos

Could you explain a little more on what you mean? I read that site you sent me and its confusing me because my setup isn't like his.

Plus im new to programming and require a little more help.

Thanks so much.
Matthew

He's using ISO-standard C++, so everything he does you can do. However, the code he provides isn't in the same order you would put it in your program, just in the order he tells you about it.

The basic strategy is that you should read all user input as a string.

#include <iostream>

int main() {
  std::string user_input;

  std::cout << "How many years old are you? ";
  std::getline( std::cin, user_input );

  return EXIT_SUCCESS;
  }

At this point, the user could have entered anything --including nothing by just pressing the ENTER key. However, since we can expect users to do dumb stuff like that, we have obtained input in a safe way: the program is still working properly.

Now, we need to verify that the user gave us a string that is correctly formatted. Since we are asking for a number, let's create some way to verify that the user did, in fact, enter a number using the digits 0..9. I'll use the same kind of technique referenced in the article.

#include <algorithm>
#include <iostream>
#include <cctype>

// This is just a fancy way of making a function that returns
// true if c is not a digit in '0'..'9'. Except, instead of a function,
// it is an object.
class nondigit {
  public:
    bool operator () ( char c ) { return !isdigit( c ); }
  };

int main() {
  std::string user_input;

  std::cout << "How many years old are you? ";
  std::getline( std::cin, user_input );

  // If the user entered anything except digits, find where
  // in the string. Notice how we create a temporary 'nondigit'
  // object to use as the test predicate.
  std::string::iterator error_iter =
    find_if( user_input.begin(), user_input.end(), nondigit() );

  // Now complain if he did, by showing him exactly where he
  // made his error.
  if (error_iter != user_input.end()) {
    std::cout << user_input << '\n'
              << std::string( error_iter -user_input.begin(), ' ' )
              << "^this is not a digit!\n";
    return 0;
    }

  return EXIT_SUCCESS;
  }

Once we have verified that the input is correct, we can convert it to an actual number. Here it is again. (This time we use a function for the test predicate instead of an object, just so you can see the difference.)

#include <algorithm>
#include <iostream>
#include <sstream>
#include <cctype>

// This is our function that returns true if c is not a digit
// in '0'..'9'.
bool nondigit( char c ) { return !isdigit( c ); }

int main() {
  std::string user_input;

  std::cout << "How many years old are you? ";
  std::getline( std::cin, user_input );

  // If the user entered anything except digits, find where
  // in the string.
  std::string::iterator error_iter =
    find_if( user_input.begin(), user_input.end(), nondigit );

  // Now complain if he did, by showing him exactly where he
  // made his error.
  if (error_iter != user_input.end()) {
    std::cout << user_input << '\n'
              << std::string( error_iter -user_input.begin(), ' ' )
              << "^this is not a digit!\n";
    return 0;
    }

  // Else convert it to an actual number
  int users_age;
  std::stringstream ss( user_input );
  ss >> users_age;

  std::cout << "So you are " << users_age << " years old.\n";

  return EXIT_SUCCESS;
  }

Ah, almost forgot. All these programs you can compile and test yourself. Try giving it both valid and invalid input. Like 12 twelve 30years 2600 moons I hope this helps.

Member Avatar for xfactornos

Thanks for your reply but I tried to use the code with mine and I had a lot of errors. One was something about a redefinition.
Im still working on it and I appreciate the responses.

I might just turn it in as is because there is nothing in our book that says what you guys are trying to teach me.

once again thanks guys


Edit:
I tried your examples and they work fine but i cant seem to integrate it into my code.

Matthew

i think this function can be of your help. You could read scores as characters and pass to this function to check for any characters in it. the function will return you with a integer value of score.

#include<iostream>
using namespace std;

int checkchar(char scores[4])
{

        int y = 0;
        int i=0;
        cin>>scores;
        while(scores[i]!='\0')  {
                if (((int) scores[i]<48) || ((int) scores[i]>57))       {
                        cout<<"The score is not a proper number \n";
                        return 1;
                }
                else
                        y = (int) scores[i] - 48 + y*10;              //to convert to integer
                i++;
        }


        return y;
}

If nothing here helps then i should say Just Google It!

Ah, yes, it is the beginning of the year... so you should be at the beginning of your programming course and not at the end...

Sorry I went over your head.

The basic principles are:

  1. always read user input as a string, using something like getline( cin, s );
  2. test the string to make sure the input is valid
  3. convert the string to the proper type of thing (integer, float, enum, etc.)

This is not lighthearted stuff. But all robust code that interfaces with the user must have it in some form. In academia people get away without it because the focus is often on other things.

There are as many ways to check input as you can think of. You could, for example, just create a function that tells you if it is good or bad.

getline( cin, s );
if (!isanumber( s )) { cout << "fooey!\n"; return; }
n = converttonumber( s )

Somewhere else you'd have defined the handy little functions isanumber() and converttonumber() to help you. The abstraction and organization of your code is up to you.

T.N.Sharma Be careful:

  • Get rid of that cin>>scores; ! It's pure evil, and getting rid of it is the whole point of this thread.
  • The argument should be char scores[] .
  • Don't hardcode ASCII values. Use '0' and '9' .
  • Your function tries to do two things but succeeds with only one.
    1. if your function determines that the input is invalid, it writes a message, but still returns a value to be used. The caller will have no idea that something is wrong and will continue on its merry way with invalid data.
    2. also, in general, utility functions should not communicate with the user, or abort the program, etc.

    The best ways to keep validation and conversion combined like you have is one of:

    1. Throw an exception if the input is invalid
    2. Return a functor type (like Haskell's 'maybe')
    3. Use reference parameters to return the number, validity, or both.
    4. Restrict the output (for example, say negative numbers are invalid and return a negative number if the input is invalid)

    It is laudable to realize that validation and conversion are closely related. The idea of making a single function to validate and convert is perfectly valid. Thanks!

Member Avatar for xfactornos

Well guys I contacted my instructor and he said not to worry with it yet. This is only our first program. He states we will learn strings later.
Thanks for all your help.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.