Newbie C++ question regarding, um... well, I don't know what it's called

The facts:
I’m using the cin bit (command? function?) to capture a number from the user. That part I’m fine with. But next I want to verify that what I’ve captured is really a number, and if it isn’t respond with an admonishment through cout. I’m fine with the cout syntax too; it’s just the verifying part that I haven’t got. I assume it look ssomething like this:

if (somethingsomething)
{
cout << “Admonishment” << endl;
}

or

if (somethingsomething)
{
cout << “Andmonishment. Instruction to input appropriate value.” << endl;
cin >> variablename;
}

But the somethingsomething part I don’t know.

I’m using codewarrior (which a friend gave to me), but what I know about c++ is what I remember from an intro c/matlab class two years ago and what I’ve figured out from experimentation in the last 9 hours. So go slowly, please.

The questions:

  1. Is what I’ve guessed above right?
  2. If so, what should I place instead of somethingsomething?
  3. Does assigning a double or int variable preclude capturing anything else? Does that require a string?
    3a) If I were to ask for a string, how would I go about verifying that it’s an acceptable one (such as an actual filename or somesuch)?
  4. How can I make the admonishment repeat until I get an acceptable number? Do I need a for loop?

I’ve tried google, but I can’t find anything about verifying strings or numbers. Lots of sites about basic syntax, though.

cin is a ‘class’ or ‘object’ (don’t ask)

I think if you enter something other than a number it yields 0. So you’d write something like

int i;
do { cin >> i; } while (i==0); //you could use !i

and it’ll go round until you get a proper number. If you need to enter 0, I don’t know what you’d do.

You’d probably have to get it as a string and then check if it’s a number or whatever. There should be some standard functions to help you - search your help for conversions, string manipulation, etc. Sorry I can’t be more help

Luckily, I don’t have to enter 0. I’ll try that.

I looked through the help file, but it wasn’t… helpful.

I believe you can use

if (IsNumeric(intNumber))
{
stufftodo;
}

I don’t recall which library the IsNumeric functions is in. It might be in stdio.h.

Okaaaaaaaaaaaaaaaaaay. Now I’m getting a link error:

“Error creating the file debug.exe.
The process cannot access the file because it is being used by another process.”

I have no idea what could be using the debug.exe for this project.
I can compile, but not run. Any suggestions?

If he’s using C++, he’s probably not using <stdio.h>, but <iostream> (he obviously is, if he’s using cin and cout). In order to test your input characters, you can #include <cctype> and use its isdigit function. For info on how to use it, look for documentation on the cctype library, or for ctype.h (the standard C library for which cctype is a wrapper).

As for your “Error creating the file. . .” message, I tend to get that when the .exe I’m trying to compile to is still open/running. That is, if I compile and test the program, and fail to close it before I build it again (or if it crashes and hangs). If you closed it, check the process list to make sure it didn’t actually crash on you.

Let’s not overcomplicate matters, shall we?

Writing totally robust console input is a major pain in the neck, but there are some relatively simple panaceas.

Here’s a program to attempt to read in an integer. On entering something other than what the cin console input object accepts as an integer, it detects the error, and then skips input from that point up to the end of the line:

#include <iostream>
#include <limits>
using namespace std;
int main()
{
int i;
cout << "Enter an integer: ";
cin >> i;
if (!cin) //something went wrong… i won’t contain a valid value
{
cin.clear(); //clear the error, to allow future input
cout << “You didn’t enter an integer.” << endl;
cin.ignore(numeric_limits<int>::max(),’
');
}
else
{
cout << "You entered: " << i << endl;
}

return 0;
}
The program is relatively simple. Just after attempting to read an integer, check the status of the cin object (in the way I did, or by testing against cin.good()!=true).

If the status is bad, then the integer didn’t really get read in so don’t trust the contents of the variable into which you were attempting to read. Throw up an error message.

The trick, though, is to get past that bad input, because some part of it or all of it is still ‘pending’ to be read. On any future attempt to read, any remaining characters in the input ‘stream’ will be read as if the user entered them… which the user did, but on a previous input.

The safest solution is to ignore to the end of the line. Probably the best robust C++ way to do that (short of spinning in a loop and reading characters until the ’
’ occurs, which is legitimate) is to use the ignore method, specifying the maximum integer possible (ignore forever, essentially) with a stopping character of ’
', the end of line.

So it ignores everything until the end of line. You could be more clever and ignore up to the next whitespace (of which ’
’ qualifies), which would enable you to still try to process stuff that’s on the line.

You could come up with more clever schemes for trying to recover.

But for many many purposes, ignoring until the end of line is the simplest.

numeric_limits is a template class in the limits header. The data type in angle brackets can be any basic type. The max() method can then be used to get the maximum value of that type. There are C-style constants that serve the same purpose and are less wordy, but aren’t as ‘C++ clean’… the value of using numeric_limits is less important than the other techniques shown here.

I should mention that there are limits to this. An attempt to enter in a floating point number like 5342.44 will still read in as an integer (the 5342 part), leaving .44 remaining in the input stream. Guarding against that (if you care) may involve reading the next character, and if its not a ‘.’, then put it back (there’s an unget method of cin that enables this for just one character, presumably the one you just pulled out with get).

Having the .44 left in there will be read in by future read operations.

Another alternative is to always skip to the end of the line after any possibly dangerous input.

The moral of the story? Always be absolutely clear on what is or can be in your input stream. It doesn’t go away just because it doesn’t seem relevant.

Yet another alternative is to read in a floating point value first, and then truncate it, but this doesn’t strictly prevent floating point values from being entered.

Oh, did I mention let’s not overcomplicate this? :smiley: Sadly, truly robust console input is a little tricky.

On the topic of using the isdigit methods and so on of the cctype header… you can process the input of cin character by character if you really want and do your own ultra-robust input checking, but for simple coursework you can get very robust code without having to resort to this level of tokenizing/parsing of input. Not that it’s that hard, but cin already has a lot of logic to handle this for you, so abuse it until it no longer suffices.

Okay, this sort of works:

i=isdigit(ni);
while (i==0 && ni==0)
{
cin.clear();
cin.ignore(numeric_limits<int>::max(),’
');
cout << “Then entered value is invalid. Please input another.” << endl;
cin >> ni;
}

The only problem (and a large one) is that isdigit seems to only check the first character. It catches k234, but not 1k23, for example.

Anys suggestions on how to fix this? Can I make isdigit check each character? Should I save the unput as a string?

Oh, and btw, from what I can tell, isnumeric exists only in vb, not in c++.

isdigit works on a single value, and is actually meant to be a character value. Since we can’t see what ni is, data type wise, or what value it was given prior to this code, there’s no real way of determining if this works.

It returns an integer that is either 0 or 1 depending on whether or not the parameter provided is a digit character.

Problem is, even my solution won’t catch 1k23 on its own. But it would be simple enough to make it do so by subsequently checking a single read character, as I suggested, and if its whitespace, then the previously read number is good.

With what you’ve provided here, yes, you will have to read in character by character, and either storing it in a string to process later into a number, or process into a number as you go.

isdigit on its own cannot be used to check an entire string. It can only check a character. To make it check more characters, feed it more… either in a loop after the fact, once you’ve read your characters into a string, or as you read in the characters.

I still prefer using cin to directly attempt to read in a value as in my example, plus an added check to see if any non-digits follow, since it means I don’t have to store or process the digit characters as I go, but that’s just me. :slight_smile: There’s more than one way to do it.

ni is a double. I didn’t originally try the first suggestion you posted because is doesn’t (or so I think - I’m not the best programmer) cycle back and demand a replacement value each time. It runs through once and stops. Right? That’s why I chose a while loop, so that the program wouldn’t go on while there was an invalid value.

Also, I don’t want an int, but I assumed that that double could be substituted. If not please let me know.

Sooooooo, How about this:

double ni;
cout << “Input number.” << endl;
cin >>ni;
while (!cin)
{
cin.clear();
cin.ignore(numeric_limits<int>::max(),’
');
cout << “Then entered value is invalid. Please input another.” << endl;
cin >> ni;
}

Would that work?
PS - Did Reginald Peach take you all the way down? How was it?

It’d work just fine, except it won’t catch that pesky bad data following good data. cin will consider it good if it’s at least able to discern a floating point value in the stream, and stop when the characters stop being a part of that number. You would want to further reject it:
double ni;
char cTemp;
cout << “Input number.” << endl;
cin >>ni;
if (cin)
cin.get(cTemp);
while (!cin || !isspace(cTemp))
{
cin.clear();
cin.ignore(numeric_limits<int>::max(),’
');
cout << “Then entered value is invalid. Please input another.” << endl;
cin >> ni;
if (cin)
cin.get(cTemp);
}
cin.unget();

  cout &lt;&lt; "You entered: " &lt;&lt; ni &lt;&lt; endl;

We read an extra character after the (hopefully valid) number if we can. We use that as extra criteria. If we get past the loop, we read a good number, and the character following was acceptable, so we put it back for future reading with the unget.

You can be more paranoid, and make sure the extra character is strictly an end of line with ’
’ instead of all whitespace (of which ’
’ is an element).

Follow me?

This way you can use cin’s natural ability to assemble the number, but still check that it read in okay, and still check that no bad stuff follows. Slightly less painful than reading in the number itself character by character and dealing with it that way. Doable, but why if you don’t have to?

Sorry for the late reply - I had to run a few errands.

William_Ashbless, I think I’m with you there. That last suggestion works like a charm. Thanks a million.

To everyone else who offered their help, many thanks. One day maybe I can return the favor.

Excellent. :smiley: