A small question

B

BKMiller

Hello everyone,

I'm just getting started playing around with C++, so please don't laugh
too loudly at my crude source code, okay? (o^^o)

I'm combining together several introductory exercises into one small
program. My compiler and IDE is Visual C++ Express Edition, and the
book I'm using is Teach Yourself C++ in 24 hours by Jesse Liberty and
David Horvath. While playing around with the code a little bit I found
something I couldn't understand.

The program only uses "int" variables (except for one small string). I
have a function called "LoopExp" that takes input from the user and
stores it in FirstNumber. LoopExp then calls another function,
"CompareNumbers" to do a quick division exercise. Naturally, I need
two numbers, so CompareNumbers gets a variable called SecondNumber from
the user.

If the user inputs a number with a decimal point for FirstNumber (i.e.,
4.5), then the CompareNumbers function pulls garbage off the stack and
will not run correctly. I tried using a forced typecast on
FirstNumber, int(FirstNumber), but naturally the compiler returned an
error.

Is there an easy way to prevent CompareNumber from pulling garbage off
the stack or do I just have to wait until I study exception handling?

The source code is below. Many thanks to anyone who takes the time to
offer a reply!

Brian K. Miller

--------------------------------------------------------------------------------------------------------------------------

#include <iostream>

using namespace std;

void LoopExp(); // Declare the LoopExp()
function
void CompareNumbers(int FN); // Declare the CompareNumbers()
function


int main()
{
char Name[64];

cout << "\nIs this thing on?" << endl;
cout << "Oh, sorry! I guess it is." << endl;
cout << "As long as I have your attention, what's your name?\t";
cin >> Name;
cout << "Hello, " << Name << ". Pleased to meet you!" << endl <<
endl;

// From this point we call some functions containing other
examples

LoopExp(); // Contains an example of a simple do-while loop

return 0;
}

void LoopExp()
{
/* This function asks for a number from the user, checks to make
sure their input is within bounds (but does NOT check for
character
input!) then outputs "I love games!" to the screen for the same
number of times as the user's input.
*/

int FirstNumber = 0;

cout << "So, let's play a game! Give me a number from 1 to 10: ";
cin >> FirstNumber;

/*
NOTE: If the user inputs a number with a decimal point (i.e.,
4.5)
for FirstNumber then the CompareNumbers() function will not
work
properly and the program will display garbage!
*/

CompareNumbers(FirstNumber);

if (FirstNumber < 1 || FirstNumber > 10) // check for an input
error
{
cout << "You're no fun!" << endl;
}
else
{
do
{
cout << "I love games!" << endl; // output the message
FirstNumber--; // decrement
the number
} while (FirstNumber != 0);
} // end of if-else

cout << endl; // move cursor down one line

} // end of LoopExp()


void CompareNumbers(int FirstNumber)
{
/* This function asks for a second number larger than the first,
but less than 100. It then uses the modulus operator to see
if they are evenly divisible. If they are, it checks to see
if the user entered 10 twice (the only possible duplication).
If the numbers are evenly divisble it outputs the correct
answer.
If they are not evenly divisble, it apologizes and outputs
the integer component of the answer.

NOTE: If the user inputs a number with a decimal point for
SecondNumber, then the program will strip off the remainder
and just use the integer portion.
*/

int SecondNumber = 0;
int Temp = 0;
int FN = 0;

FN = FirstNumber;

cout << "Now give me a number between 10 and 100: ";
cin >> SecondNumber;

if (SecondNumber < 10 || SecondNumber > 100) // check for an
input error
{
cout << "Hey! " << SecondNumber << " is not what I asked for!"
<< endl;
}
else
{
Temp = SecondNumber / FN;

if ((SecondNumber % FN) == 0) // check if they are evenly
divisble
{
if (SecondNumber == FN)
{
cout << "You really like the number 10, don't you?" <<
endl;
}
else
{
cout << "\nOh, cool! They are evenly divisible!" <<
endl;
cout << "The second number divided by the first is: " <<
Temp << endl << endl;
} // end of "Oh, cool!"
} // end of "check for evenly divisible"
else
{
cout << "\nI tried to divide " << SecondNumber << " by " <<
FN;
cout << ", but I can't do fractions." << endl;
cout << "Still, " << Temp << " is pretty close, right?" <<
endl << endl;
} // end of "I can't do fractions"
} // end of else section following initial error check for
SecondNumber
} // end of CompareNumber()
 
D

Dietmar Kuehl

BKMiller said:
If the user inputs a number with a decimal point for FirstNumber (i.e.,
4.5), then the CompareNumbers function pulls garbage off the stack and
will not run correctly.

Well, more precisely, 'FirstNumber' will become "4" and the next
character to be read will be "." which is not a valid start for
an 'int'. Thus, the next attempt to read an 'int' from the stream
will fail, set corresponding state flags in the stream, and leave
the corresponding variable uninitialized.

You should always check the result from input, especially if it is
manual input. This could look like this:

if (std::cin >> var)
/* processing of successful read goes here */
else
/* processing of wrong input goes here */

Depending on what you are doing, recovery from an input error may
take different forms. In your situation you probably want to try
to recover from the error situation, e.g. by ignoring everything
on the current line:

// execute the loop until we could either successfully read
// a value or end of file is reached:
while (!(std::cin >> var) && !std::cin.eof())
{
std::cin.clear(); // clear the error flags
// ignore an arbitrary amount of character until end of line
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
if (std::cin.eof())
throw std::runtime_error("EOF while reading a value");

In many situations no recovery is attempted and the processing of
the file is immediately terminated with an appropriate error.
Is there an easy way to prevent CompareNumber from pulling garbage off
the stack

Actually, this is not at all happening.
char Name[64];
cin >> Name;

This is a receipt for buffer overflows! There are two options to
make sure that no buffer overflow occurs:

1. The preferred option is to use an 'std::string' instead of a
fixed size array:

#include <string>
// ...
std::string Name;
std::cin >> Name;

This is less error-prone and accommodates for the possible use
of rather long names.

2. You can setup the maximum number of characters to be read by
setting the width:

#include <iomanip>
// ...
char Name[64];
std::cin >> std::setw(sizeof(Name)) >> Name;

This will limit the number to be read to be 'sizeof(Name) - 1'.
The extra character is need to store a terminating null character.
 
Z

Zara

On 27 Feb 2006 22:56:32 -0800 said:
Is there an easy way to prevent CompareNumber from pulling garbage off
the stack or do I just have to wait until I study exception handling?

Yes, test if input conversion has failed
void LoopExp()
{
/* This function asks for a number from the user, checks to make
sure their input is within bounds (but does NOT check for
character
input!) then outputs "I love games!" to the screen for the same
number of times as the user's input.
*/

int FirstNumber = 0;

cout << "So, let's play a game! Give me a number from 1 to 10: ";
cin >> FirstNumber;

/*
NOTE: If the user inputs a number with a decimal point (i.e.,
4.5)
for FirstNumber then the CompareNumbers() function will not
work
properly and the program will display garbage!
*/

if (cin.fail()) {/*Do whatever you think is fit */}
CompareNumbers(FirstNumber);
void CompareNumbers(int FirstNumber)
{
/* This function asks for a second number larger than the first,
but less than 100. It then uses the modulus operator to see
if they are evenly divisible. If they are, it checks to see
if the user entered 10 twice (the only possible duplication).
If the numbers are evenly divisble it outputs the correct
answer.
If they are not evenly divisble, it apologizes and outputs
the integer component of the answer.

NOTE: If the user inputs a number with a decimal point for
SecondNumber, then the program will strip off the remainder
and just use the integer portion.
*/

int SecondNumber = 0;
int Temp = 0;
int FN = 0;

FN = FirstNumber;

cout << "Now give me a number between 10 and 100: ";
cin >> SecondNumber;

if (cin.fail()) {/*Do whatever you think is fit */}
if (SecondNumber < 10 || SecondNumber > 100) // check for an
input error
{
cout << "Hey! " << SecondNumber << " is not what I asked for!"
<< endl;
}
else
{
Temp = SecondNumber / FN;

if ((SecondNumber % FN) == 0) // check if they are evenly
divisble
{
if (SecondNumber == FN)
{
cout << "You really like the number 10, don't you?" <<
endl;
}
else
{
cout << "\nOh, cool! They are evenly divisible!" <<
endl;
cout << "The second number divided by the first is: " <<
Temp << endl << endl;
} // end of "Oh, cool!"
} // end of "check for evenly divisible"
else
{
cout << "\nI tried to divide " << SecondNumber << " by " <<
FN;
cout << ", but I can't do fractions." << endl;
cout << "Still, " << Temp << " is pretty close, right?" <<
endl << endl;
} // end of "I can't do fractions"
} // end of else section following initial error check for
SecondNumber
} // end of CompareNumber()


Regards,

Zara
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top