Hello all.

I am working on a little program here and need some help. The input is 3 test grades that are out of 50 points total, the program takes the higher of the first 2 test grades and adds that to the last test grade to determine a final score.

This is where I need my first bit of help, as you can see the code below isn't quite up to par. It will correctly give you a final grade, but it also gives 2 other grades in addition because of how I set up the if statements. I'm not sure where to add an else because I don't want it to say if you dont get an A then else you get BCDF or something. I was trying to use the && or || possibly but can't figure out how to get what I want.

Also I need help verifying the input the user enters, if they enter negative numbers or letters it crashes the program. Like something that prompts the user "no negative numbers, try again".

# include <string>
# include <iostream>

using namespace std;

int main()

{
	string name;
	float test1;
	float test2;
	float test3;

	cout << "Welcome to the Grade Calculator Machine.  You will enter three test scores." <<endl;
	cout << "The higher of the first two test grades will be added with the third test grade" <<endl;
	cout << "to determine the final grade average for the course." <<endl<<endl;

	cout <<"Enter the student's name:";
	getline(cin, name);

	cout <<"Please enter test score 1:";
	cin >> test1;

	cout <<"Please enter test score 2:";
	cin >> test2;

	cout <<"Please enter test score 3:";
	cin >> test3;
	
if

(test1 > test2)
cout <<"The average for the course = " <<((test1 + test3)/2)*2<<endl;

else
cout <<"The average for the course = " <<((test2 + test3)/2)*2<<endl;


if
((((test1 + test3)/2)*2) >= 90) 
cout<<name<<" has earned an A for the course."<<endl;
if
((((test2 + test3)/2)*2) >= 90) 
cout<<name<<" has earned an A for the course."<<endl;
if
((((test1 + test3)/2)*2) >= 80 && (((test1 + test3)/2)*2) <=89)
cout<<name<<" has earned a B for the course."<<endl;
if
((((test2 + test3)/2)*2) >= 80 && (((test2 + test3)/2)*2) <=89)
cout<<name<<" has earned a B for the course."<<endl;
if
((((test1 + test3)/2)*2) >= 70 && (((test1 + test3)/2)*2) <=79)
cout<<name<<" has earned a C for the course."<<endl;
if
((((test2 + test3)/2)*2) >= 70 && (((test2 + test3)/2)*2) <=79)
cout<<name<<" has earned a C for the course."<<endl;
if
((((test1 + test3)/2)*2) >= 60 && (((test1 + test3)/2)*2) <=69)
cout<<name<<" has earned a D for the course."<<endl;
if
((((test2 + test3)/2)*2) >= 60 && (((test2 + test3)/2)*2) <=69)
cout<<name<<" has earned a D for the course."<<endl;
if
((((test1 + test3)/2)*2) < 60)
cout<<name<<" has earned an F for the course."<<endl;
if
((((test1 + test3)/2)*2) <60)
cout<<name<<" has earned an F for the course."<<endl;



cout<< "\n \n \nThank you for using the Grade Calulator Machine"<<endl;

return 0;
}

You can change your if statements to else if statements and simplify them:

if
((((test1 + test3)/2)*2) >= 90) 
cout<<name<<" has earned an A for the course."<<endl;
else if
((((test2 + test3)/2)*2) >= 90) 
cout<<name<<" has earned an A for the course."<<endl;
else if
((((test1 + test3)/2)*2) >= 80)
cout<<name<<" has earned a B for the course."<<endl;
else if
((((test2 + test3)/2)*2) >= 80)
cout<<name<<" has earned a B for the course."<<endl;
else if
((((test1 + test3)/2)*2) >= 70)
cout<<name<<" has earned a C for the course."<<endl;
else if
((((test2 + test3)/2)*2) >= 70)
cout<<name<<" has earned a C for the course."<<endl;
else if
((((test1 + test3)/2)*2) >= 60)
cout<<name<<" has earned a D for the course."<<endl;
else if
((((test2 + test3)/2)*2) >= 60)
cout<<name<<" has earned a D for the course."<<endl;
else
    cout<<name<<" has earned an F for the course."<<endl;

You may also want to set up a variable:

float score;
if (test1 > test2)
    score = (test1 + test3) / 2;
else
    score = (test2 + test3) / 2;

then use that variable:

if (score >= 90)
    cout<<name<<" has earned an A for the course."<<endl;
else if (score >= 80)
    cout<<name<<" has earned an B for the course."<<endl;
// etc.

Wow thanks! I really wanted to create an "in between" variable to store the score, just didn't know what it was called. I will try this later today but it looks like it will solve a lot of my problems.

Thanks!

Wow thanks! I really wanted to create an "in between" variable to store the score, just didn't know what it was called. I will try this later today but it looks like it will solve a lot of my problems.

Thanks!

You're welcome. I just noticed this though.

if
((((test1 + test3)/2)*2) >= 90)

Looks like you are dividing by 2, then multiplying by 2, which cancel each other out, so do you want to simplify it to this?

if
(test1 + test3 >= 90)

You're welcome. I just noticed this though.

if
((((test1 + test3)/2)*2) >= 90)

Looks like you are dividing by 2, then multiplying by 2, which cancel each other out, so do you want to simplify it to this?

if
(test1 + test3 >= 90)

Hehe yeah I noticed that as well. I originally intended the program to take an average of the two numbers before I realized I only had test scores that were out of 50 points :).

I've been reading around on input verification and have only come across one way that may work. It created a 2 character array to enter the numbers and then converts the character to # and if that fails it prompts the users to enter only numbers.

Just wondering if that's the easiest way to approach this?

Hehe yeah I noticed that as well. I originally intended the program to take an average of the two numbers before I realized I only had test scores that were out of 50 points :).

I've been reading around on input verification and have only come across one way that may work. It created a 2 character array to enter the numbers and then converts the character to # and if that fails it prompts the users to enter only numbers.

Just wondering if that's the easiest way to approach this?

You have the scores set as floats, so you may need more than two characters since I assume 49.5 is legal input? There are a variety of ways to do it. I'd read the data in as a string, then go through it character by character with isdigit. Check for a decimal too. After that, convert it to a double (you may need to change the floats to doubles in your program) in any number of ways. You can write your own function or you can use strtod.

Ok so I've been working on this and still cant really get it figured out.

Does atoi convert it to a number?

Here is what i was trying:

string test1;

cout<<"enter test 1:";
	cin>>test1;
if (isdigit(str[0]))
  {
test1= atoi (str)
}
test11 = strtod (test1);

I'm lost as you can see....

Not sure if I should call the test score variables string or double?

And I'm not sure if I need to use another variable instead of just test1 with strtod thats why I was using test11...I'm not much of a progammer :(.

Ok so I've been working on this and still cant really get it figured out.

Does atoi convert it to a number?

Here is what i was trying:

string test1;

cout<<"enter test 1:";
	cin>>test1;
if (isdigit(str[0]))
  {
test1= atoi (str)
}
test11 = strtod (test1);

I'm lost as you can see....

Not sure if I should call the test score variables string or double?

And I'm not sure if I need to use another variable instead of just test1 with strtod thats why I was using test11...I'm not much of a progammer :(.

You have to read the documentation, try out the samples, and experiment. Pay attention to the function prototypes:

http://www.cplusplus.com/reference/string/string/c_str.html
http://www.cplusplus.com/reference/clibrary/cstdlib/atoi.html
http://www.cplusplus.com/reference/clibrary/cstdlib/atof.html

I linked strtod in the previous post:

atoi returns an integer. If you want a float or a double, you need to use something else.

int atoi ( const char * str );

atof returns a double, so that's better. it's basically the same as strtod, but strtod is considered "safer", I think. You can use either, but I think strtod is generally considered better.

double atof ( const char * str );

None of these functions takes a string as an argument. They take C-Strings (char*), so you need something to convert them, which is where the string::c_str function comes in (see link above):

const char* c_str ( ) const;
string test1;

cout<<"enter test 1:";
	cin>>test1;
if (isdigit(str[0]))
  {
test1= atoi (str)
}
test11 = strtod (test1);

It's hard to see what you are doing here since you have this variable called str that you must have declared earlier, but don't post here. I assume it's a char*, but you need to post that code in your snippet too. Regardless, it's wrong, since atoi returns an integer and you have declared test1 to be a string, so you are assigning an integer to a string, which is a type mismatch.

You have to read the documentation, try out the samples, and experiment. Pay attention to the function prototypes:

http://www.cplusplus.com/reference/string/string/c_str.html
http://www.cplusplus.com/reference/clibrary/cstdlib/atoi.html
http://www.cplusplus.com/reference/clibrary/cstdlib/atof.html

I linked strtod in the previous post:

atoi returns an integer. If you want a float or a double, you need to use something else.

int atoi ( const char * str );

atof returns a double, so that's better. it's basically the same as strtod, but strtod is considered "safer", I think. You can use either, but I think strtod is generally considered better.

double atof ( const char * str );

None of these functions takes a string as an argument. They take C-Strings (char*), so you need something to convert them, which is where the string::c_str function comes in (see link above):

const char* c_str ( ) const;

Ok so I would want

string test1;
const char* c_str (test1 ) const;

I really need someone to spell out an example similiar to what I'm doing, sorry this stuff just goes right over my head.

My program works fine and I was really proud, but this verifying input has got me down in the dumps.

Here is an example. It's not perfect and lets some bad input go by, but it's an example:

#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;

int main ()
{
    string userInput;
    double score;
    cout << "Enter a non-negative number: ";
    cin >> userInput;
    score = strtod (userInput.c_str (), NULL);
    if (score > 0)
        cout << "Score is " << score << endl;
    else if (score < 0)
        cout << "Invalid.  You entered a negative number." << endl;
    else
        cout << "You entered either 0 or an invalid number." << endl;
    
    return 0;
}

Here's the function spec. See red.

double strtod ( const char * str, char ** endptr );

Convert string to double

Parses the C string str interpreting its content as a floating point number and returns its value as a double. If endptr is not a null pointer, the function also sets the value pointed by endptr to point to the first character after the number.

The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes as many characters as possible that are valid following a syntax resembling that of floating point literals, and interprets them as a numerical value. A pointer to the rest of the string after the last valid character is stored in the object pointed by endptr.

A valid floating point number for strtod is formed by a succession of:

* An optional plus or minus sign
* A sequence of digits, optionally containing a decimal-point character
* An optional exponent part, which itself consists on an 'e' or 'E' character followed by an optional sign and a sequence of digits.

If the first sequence of non-whitespace characters in str does not form a valid floating-point number as just defined, or if no such sequence exists because either str is empty or contains only whitespace characters, no conversion is performed.

Parameters

str
C string beginning with the representation of a floating-point number.
endptr
Reference to an already allocated object of type char*, whose value is set by the function to the next character in str after the numerical value.
This parameter can also be a null pointer, in which case it is not used.

Return Value
On success, the function returns the converted floating point number as a double value.
If no valid conversion could be performed, a zero value (0.0) is returned.
If the correct value is out of the range of representable values, a positive or negative HUGE_VAL is returned, and the global variable errno is set to ERANGE.
If the correct value would cause underflow, zero is returned and errno is set to ERANGE.

Thus, if the user inputs "43f", it'll return 43. If the user enters "f", it'll return 0. this example doesn't make a distinction between bad data being entered and 0 being entered. If you need to catch THAT too, you'll need something more than this example does.

string test1;
	double score1;

cout <<"Please enter test score 1:";
	cin >> test1;
	score1 = strtod (test1.c_str (), NULL);
  if (score1 > 0)
        cout << "Score is " << score1 << endl;
    else if (score1 < 0)
        cout << "Invalid.  You entered a negative number." << endl;
    else
        cout << "You entered either 0 or an invalid number." << endl;

I get a really long error message when I try this. Starts off like this...really really long:
error C2676: binary '/' : 'std::basic_string<_Elem,_Traits,_Ax>' does not define this operator or a conversion to a type acceptable to the predefined operator
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>,
1> _Ax=std::allocator<char>
1> ]
1>c:\users\austin\documents\visual studio 2005\projects\scores\scores\scoresc.cpp(62) : error C2676: binary '/' : 'std::basic_string<_Elem,_Traits,_Ax>' does not define this operator or a conversion to a type acceptable to the predefined operator
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>,
1> _Ax=std::allocator<char>
1> ]
1>c:\users\austin\documents\visual studio 2005\projects\scores\scores\scoresc.cpp(66) : error C2784: 'bool std::operator >=(const std::basic_string<_Elem,_Traits,_Alloc> &,const _Elem *)' : could not deduce template argument for 'const _Elem *' from 'int'
1> c:\program files\microsoft visual studio 8\vc\include\string(241) : see declaration of 'std::operator >='
1>c:\users\austin\documents\visual studio 2005\projects\scores\scores\scoresc.cpp(66) : error C2784: 'bool std::operator >=(const _Elem *,const std::basic_string<_Elem,_Traits,_Alloc> &)' : could not deduce template argument for 'const _Elem *' from 'std::basic_string<_Elem,_Traits,_Ax>'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>,
1> _Ax=std::allocator<char>

Copy and paste my program verbatim. No more, no less. See if it runs as is, without trying to integrate into your program. Start a new empty project if need be. It should compile and run as is. If it doesn't, post the errors. The snippet you posted looks identical to my code, just with different variable names, so it should be fine. If MY code works as is (I can't think of any reason it wouldn't) and yours doesn't, then post your entire program, not just this snippet. The part you posted looks fine, so I'm guessing the problem is somewhere else.

# include <string>
# include <iostream>
# include <cstdlib>

using namespace std;

int main()

{
	string name;
	string test1;
	double score1;
	string test2;
	double score2;
	string test3;
	double score3;


	cout << "Welcome to the Grade Calculator Machine.  You will enter three test scores." <<endl;
	cout << "The higher of the first two test grades will be added with the third test grade" <<endl;
	cout << "to determine the final grade average for the course." <<endl<<endl;

	cout <<"Enter the student's name:";
	getline(cin, name);

	cout <<"Please enter test score 1:";
	cin >> test1;
	score1 = strtod (test1.c_str (), NULL);
  if (score1 > 0)
        cout << "Score is " << score1 << endl;
    else if (score1 < 0)
        cout << "Invalid.  You entered a negative number." << endl;
    else
        cout << "You entered either 0 or an invalid number." << endl;

	cout <<"Please enter test score 2:";
	cin >> test2;
		score2 = strtod (test2.c_str (), NULL);
  if (score2 > 0)
        cout << "Score is " << score2 << endl;
    else if (score2 < 0)
        cout << "Invalid.  You entered a negative number." << endl;
    else
        cout << "You entered either 0 or an invalid number." << endl;

	cout <<"Please enter test score 3:";
	cin >> test3;
		score3 = strtod (test3.c_str (), NULL);
  if (score3 > 0)
        cout << "Score is " << score3 << endl;
    else if (score3 < 0)
        cout << "Invalid.  You entered a negative number." << endl;
    else
        cout << "You entered either 0 or an invalid number." << endl;
	
if

(test1 > test2)
cout <<"The average for the course = " <<((test1 + test3)/2)*2<<endl;

else
cout <<"The average for the course = " <<((test2 + test3)/2)*2<<endl;


if
((test1 + test3) >= 90) 
cout<<name<<" has earned an A for the course."<<endl;
else if
((test2 + test3) >= 90) 
cout<<name<<" has earned an A for the course."<<endl;
else if
((test1 + test3) >= 80)
cout<<name<<" has earned a B for the course."<<endl;
else if
((((test2 + test3)/2)*2) >= 80)
cout<<name<<" has earned a B for the course."<<endl;
else if
((((test1 + test3)/2)*2) >= 70)
cout<<name<<" has earned a C for the course."<<endl;
else if
((((test2 + test3)/2)*2) >= 70)
cout<<name<<" has earned a C for the course."<<endl;
else if
((((test1 + test3)/2)*2) >= 60)
cout<<name<<" has earned a D for the course."<<endl;
else if
((((test2 + test3)/2)*2) >= 60)
cout<<name<<" has earned a D for the course."<<endl;
else
    cout<<name<<" has earned an F for the course."<<endl;



cout<< "\n \n \nThank you for using the Grade Calulator Machine"<<endl<<endl<<endl;

return 0;
}

line 59: why are you attempting to so math on std::string objects? test1 and test2 are std::strings, you can't divide them by 2 then multiply them by 2 like that line is attempting to do.

Yeah I'm not sure. Giving up on verifying input, just dont enter the wrong stuff in the program.

Yeah I'm not sure. Giving up on verifying input, just dont enter the wrong stuff in the program.

It's just a question of consistency. You changed variable names/types in part of the program, but not the rest of it. Try replacing test with score in the variable names after line 56 and see if that works better. The score variables are doubles, the test variables are temp variables that you don't want to use again after your data is verified.

I figured this out, what worked for me anyway:

while (!cin || user_number < 1 || user_number > 100) //makes sure no non-integers are entered

      {

            cout << "Invalid value entered.  Please enter an integer between 1 and 100: ";

            cin.clear();   //reset the read to good

            cin.sync();       //clear out the contents of the input buffer

            cin >> user_number;

      }
This article has been dead for over six months. Start a new discussion instead.