Hello all,

I am in the process of teaching myself c++. I wrote one program successfully and I'm trying to write my second. I have run into a problem that I can not seem to figure out at all. I understand that this seems trivial, but I really need to grasp why this isn't working. The idea behind the program is that the user enters 5 baseball players' names and batting averages. The user is then prompted to enter a player's name to receive their average. Here is the code:

#include <iostream>
#include <cstring>

using namespace std;

void displayInstructions(void)
{
	cout << "This program is created to allow you to enter \n"
		 << "up to 5 baseball players' names and averages and then \n"
		 << "enter a player's name to receive their average. \n"
		 << endl;

	cout << "To stop entering names, enter the word 'end' when asked \n"
		 << "for the player's name."
		 << endl;
}

int main()
{
	class ballPlayer{
	public:
		char name[30];
		int avg;
					 };

	displayInstructions();

	int i=0;
	int players=0;
	int totalPlayers=0;
	ballPlayer player[5];
	char quit[]="end";
	
	for(i=0;i<=4;i++)
	{
		cout << "Please enter a player's name:"
			 << endl;
		cin.getline(player[players].name,30);

		if(player[0].name == "end")
		{
			cout << "Please enter at least one batter's name."
				 << endl;
			cin.getline(player[players].name,30);
		}
		else if(player[players].name == quit && i != 0)
		{
			break;
		}

		cout << "Please enter this player's average:"
			 << endl;
		cin >> player[players].avg;

		if(player[players].avg > 1000)
		{
			cout << "This is not a valid batter's average. \n"
				 << endl;
			cout << "Please enter a valid bater's average:"
				 << endl;
			cin >> player[players].avg;
			players++;
			totalPlayers++;
		}
		else
		{
		players++;
		totalPlayers++;
		}
	}

	char endBatter[30];
enterName:
	cout << "Enter the player's name to get their average:"
		 << endl;
	cin >> endBatter[0];

	players=0;
	for(i=0;i<=totalPlayers;i++)
	{
		int isMatch = strcmp(player[players].name,endBatter);

		if(isMatch == 0)
		{
			cout << player[players].name << "'s average is: "
				 << player[players].avg << endl;
continueDecision:
			cout << "Would you like to enter another player? Y/N"
				 << endl;
			char yesNo[4];
			cin.getline(yesNo,4);

			if(yesNo == "y" || yesNo == "Y")
			{
				goto enterName;
			}
			else if(yesNo == "n" || yesNo == "N")
			{
				break;
			}
			else
			{
				cout << "You did not enter a valid answer."
					 << endl;
					 goto continueDecision;
			}

			if(isMatch != 0 && players == totalPlayers)
			{
				cout << "You did not enter a valid player's name. \n"
					 << endl;
				goto enterName;
			}
		}
	}
	return 0;
}

As of right now, everything goes smoothly up until after the user enters the first player's batting average. It then prompts the following:

"Please enter a player's name:
Please enter this player's average:"

Here are the problems I am experiencing:

1. It doesn't allow users to enter the batter names of the final four players, only their averages. Because of this, I can not test the portion of code that has the user enter the word "end" to stop entering players.

2. When I enter the word "end" for the first batter, the program should prompt that the user needs to enter at least one batter, but instead it just accepts "end" as the player's name.

3. After the user enters the name of the batter that they want to receive the average for, the program quits instead of running the loop to display the correct average.

I understand that this code is most likely severely flawed and poorly written, but any help would be much appreciated and would greatly aid me in better understanding this language.

-D

Comments
Code tags on first post!

You can't simply compare 2 strings with operator ==. There is a function in library <string> called strcmp().

Syntax:
   int strcmp(string1, string2)

Return:
   Return 1 if string1 > string2
   Return 0 if string1 == string2
   Return -1 if string1 < string2.

You can't simply compare 2 strings with operator ==. There is a function in library <string> called strcmp().

Syntax:
   int strcmp(string1, string2)

Return:
   Return 1 if string1 > string2
   Return 0 if string1 == string2
   Return -1 if string1 < string2.

I used that in a portion of my code, but should I also use it in the following portion instead of the == operator?

if(player[0].name == "end")

and

else if(player[players].name == quit && i != 0)

since both of those compare 2 strings?

You wouldn't happen to have any idea why I can only enter the the first player's name and only the average for all other players?

Thanks for the help!

-D

You can't simply compare 2 strings with operator ==. There is a function in library <string> called strcmp().

Syntax:
   int strcmp(string1, string2)

Return:
   Return 1 if string1 > string2
   Return 0 if string1 == string2
   Return -1 if string1 < string2.

FWIW, the standard definition for the return value is:

The strcmp function returns an integer greater than, equal to, or less than zero, accordingly as the string pointed to by s1 is greater than, equal to, or less than the string

The strcmp function returns an integer greater than, equal to, or less than zero, accordingly as the string pointed to by s1 is greater than, equal to, or less than the string

My bad :(

You are totally right.

Thanks guys,

so I've gone through and replaced those areas where I was using the == operator with the strcmp() function.

Now can anybody point me in the right direction as to why both of my loops aren't working? (The first doesn't let me enter the names of players 2-5 and the second doesn't get farther than letting me enter the player's name.)

Thanks again.

-D

Here are the two above-mentioned for loops that I'm having trouble with:

int i=0;
	int players=0;
	int totalPlayers=0;
	ballPlayer player[5];
	
	for(i=0;i<=4;i++)
	{
		cout << "Please enter a player's name:"
			 << endl;
		cin.getline(player[players].name,30);

		if(strcmp(player[0].name,"end") == 0)
		{
			cout << "Please enter at least one batter's name."
				 << endl;
			cin.getline(player[players].name,30);
		}
		else if(strcmp(player[players].name,"end") == 0 && i != 0)
		{
			break;
		}

		cout << "Please enter this player's average:"
			 << endl;
		cin >> player[players].avg;

		if(player[players].avg > 1000)
		{
			cout << "This is not a valid batter's average. \n"
				 << endl;
			cout << "Please enter a valid bater's average:"
				 << endl;
			cin >> player[players].avg;
			players++;
			totalPlayers++;
		}
		else
		{
		players++;
		totalPlayers++;
		}
	}

and

players=0;
	for(i=0;i<=totalPlayers;i++)
	{
		int isMatch = strcmp(player[players].name,endBatter);

		if(isMatch == 0)
		{
			cout << player[players].name << "'s average is: "
				 << player[players].avg << endl;
continueDecision:
			cout << "Would you like to enter another player? Y/N"
				 << endl;
			char yesNo[4];
			cin.getline(yesNo,4);

			if(strcmp(yesNo,"y") == 0 || strcmp(yesNo,"Y") == 0)
			{
				goto enterName;
			}
			else if(strcmp(yesNo,"n") == 0 || strcmp(yesNo,"N") == 0)
			{
				break;
			}
			else
			{
				cout << "You did not enter a valid answer."
					 << endl;
					 goto continueDecision;
			}

			if(isMatch != 0 && players == totalPlayers)
			{
				cout << "You did not enter a valid player's name. \n"
					 << endl;
				goto enterName;
			}
		}
	}

Thanks guys!

-D

for(i=0;i<=4;i++)
	{
		cout << "Please enter a player's name:"
			 << endl;
		cin.getline(player[players].name,30);

		if(player[0].name == "end")
		{
			cout << "Please enter at least one batter's name."
				 << endl;
			cin.getline(player[players].name,30);
		}
		else if(player[players].name == quit && i != 0)
		{
			break;
		}

		cout << "Please enter this player's average:"
			 << endl;
		cin >> player[players].avg;

		if(player[players].avg > 1000)
		{
			cout << "This is not a valid batter's average. \n"
				 << endl;
			cout << "Please enter a valid bater's average:"
				 << endl;
			cin >> player[players].avg;
			players++;
			totalPlayers++;
		}
		else
		{
		players++;
		totalPlayers++;
		}
	}

You aren't using i as a loop variable very much. You have a variable called players that basically functions as your loop variable instead. Fine, but make sure you keep them straight.

Lines 7 through 12 need to be in a loop and it should be a while loop. You need to allow the user to make as many mistakes as he wants and still get a chance to correct it. That means a while loop, not a simple if statement. The condition to get past it is: You can't be on player 0 and type "end". Keep checking that. It's the guardian at the gate. They can't get past that till they give good input. Hence, while loop. Replace the "if" on line 7 with "while", but that means you have to change the "else if" on line 13 with "if".

Lines 22 - 31 - same idea. You need a while loop, not an if-statement. You don't get out of that while loop until you enter valid input. Thus, the number of players can't be incremented inside that while loop. You've successfully entered a player when you've passed the test that checked for good data. Hence you don't increment until AFTER the while loop is over. Consider someone who enters 2000 hundreds of times before finally getting it right. Do you have 2000 players? No. In general, data validation takes place in a while loop.

You aren't using i as a loop variable very much. You have a variable called players that basically functions as your loop variable instead. Fine, but make sure you keep them straight.

Lines 7 through 12 need to be in a loop and it should be a while loop. You need to allow the user to make as many mistakes as he wants and still get a chance to correct it. That means a while loop, not a simple if statement. The condition to get past it is: You can't be on player 0 and type "end". Keep checking that. It's the guardian at the gate. They can't get past that till they give good input. Hence, while loop. Replace the "if" on line 7 with "while", but that means you have to change the "else if" on line 13 with "if".

Lines 22 - 31 - same idea. You need a while loop, not an if-statement. You don't get out of that while loop until you enter valid input. Thus, the number of players can't be incremented inside that while loop. You've successfully entered a player when you've passed the test that checked for good data. Hence you don't increment until AFTER the while loop is over. Consider someone who enters 2000 hundreds of times before finally getting it right. Do you have 2000 players? No. In general, data validation takes place in a while loop.

Good to know. I will change that tonight. With that said, is there any instance in the second for loop that I listed above (and again below) where I should replace on of my If statements with a While loop?

for(i=0;i<=totalPlayers;i++)
{
           int isMatch = strcmp(player[players].name,endBatter);

           if(isMatch == 0)
            {
	     cout << player[players].name << "'s average is: "
	             << player[players].avg << endl;
continueDecision:
	     cout << "Would you like to enter another player? Y/N"
	             << endl;
	     char yesNo[4];
	     cin.getline(yesNo,4);

	     if(strcmp(yesNo,"y") == 0 || strcmp(yesNo,"Y") == 0)
	     {
		goto enterName;
	     }
	     else if(strcmp(yesNo,"n") == 0 || strcmp(yesNo,"N") == 0)
	     {
		break;
	     }
	     else
	     {
		cout << "You did not enter a valid answer."
		       << endl;
		goto continueDecision;
	     }

	     if(isMatch != 0 && players == totalPlayers)
	    {
		cout << "You did not enter a valid player's name. \n"
	                        << endl;
		goto enterName;
	     }
           }
}

(I didn't know you could list the code with cplusplus syntax, I hope that makes this easier to read...) Again, thanks to everybody for your input. I realize this is an incredibly pointless and mundane program, but I am still trying to understand the basics of the language.

-D

Yes, C++ code tags can be very handy. Everyone starts out with programs like these. It's like everything else. Once you've done it for a while, it'll seem easy. Programs like these are perfect for you right now. No one is going to buy it or use it for real, but that' not the point right now. I recently learned Perl and Javascript. What's easy for me to do in C++ and Java is incredibly difficult in Perl and Javascript right now.

Back to your program. At this point, you have all of the data. Your process is this:

  1. Ask user for a name.
  2. Look for that name and see if it exists.
  3. If name exists, display the information.
  4. If name doesn't exist, tell the user.
  5. Ask the user whether he/she wants to enter another name.
  6. If he/she does, go to step 1.
  7. If he/she doesn't, exit the program.
  8. If neither 6 or 7, display an error message and go back to step 5.

How many times something happens tells you if you need a loop and what kind of loop you need and whether you potentially have to "break out" of that loop (if it exists).

Steps 1 - 8 can happen more than once. Hence, loop. Is there an upper limit of how many times they can happen? No. Hence, while loop.

Step 2 - Is there a maximum number of players to check? Yes. Hence, for-loop instead of while loop. numPlayers should be in that for-loop somewhere.

Steps 3 and 4. Happens at most once. No loop. These steps are after the for-loop, so they can't happen WITHIN the for-loop. This is an if statement, or an if-else statement.

Steps 5 through 8 - How many times can a user enter bad data? Infinite. Hence, while loop.

In general, replace goto with a while loop. goto is legal C++ code, but frowned on when it can replaced with a while statement. Everything ends up being basically a goto statement, but let the COMPILER do that, not you.

So your basic outline could be this:

string yesNo = "Y";  // prime the while loop
while (yesNo == "Y" || yesNo == "y")
{
    // ask for a name
    int isMatch = 1; // prime isMatch
    for (player = 0; player < numPlayers && isMatch != 0; player++)
    {
        // calculate isMatch.  When isMatch equals 0, loop gets cut short
    }

    // check isMatch.  If it equals 0, you have a match.  Display the info for player.
    // if isMatch does not equal 0, display info that the player wasn't found.

    bool validData = false; // prime validData
    while (!validData)
    {
        // ask user for yesNo.  If user enters "Y", "N", "y", or "n", flag
        // validData as true.  Otherwise, display an error message.
    }
}
Comments
The key is: step by step :)

VernonDozier,

Thank you so much for this info. I'm going to work on this tonight and see what comes of it. I guess I never really throught of putting the entirety of that portion of the program within a While loop, but it makes perfect sense.

Thanks again.

-D

I think this is more in line with what the program needs to be. I took your outline into consideration. I haven't been able to test this yet as I am at work and don't have a compiler on my work PC, but please let me know if you see anything else that sticks out as incorrect in the code.

#include <iostream>
#include <cstring>

using namespace std;

void displayInstructions(void)
{
      cout << "This program is created to allow you to enter \n"
              << "up to 5 baseball players' names and averages and then \n"
              << "enter a player's name to receive their average. \n"
              << endl;

      cout << "To stop entering names, enter the word 'end' when asked \n"
              << "for the player's name."
              << endl;
}

int main()
{
      class ballPlayer{
      public:
           char name[30];
           int avg;
	              };

      displayInstructions();

      int players=0;
      int totalPlayers=0;
      ballPlayer player[5];
	
      for(players=0;players<=4;players++)
      {
	cout << "Please enter a player's name:"
	        << endl;
	cin.getline(player[players].name,30);

	while(strcmp(player[0].name,"end") == 0)
	{
	         cout << "Please enter at least one batter's name."
		 << endl;
	         cin.getline(player[players].name,30);
	}
	if(strcmp(player[players].name,"end") == 0 && players != 0)
	{
		break;
	}

	cout << "Please enter this player's average:"
	        << endl;
	cin >> player[players].avg;

	while(player[players].avg > 1000)
	{
		cout << "This is not a valid batter's average. \n"
	   	        << endl;
		cout << "Please enter a valid bater's average:"
		        << endl;
		cin >> player[players].avg;
	}
	totalPlayers++;

      }

      while(yesNo == "y" || yesNo == "Y")
      {
	char endBatter[30];
	cout << "Enter the player's name to get their average:"
	       << endl;
	cin.getline(endBatter,30);

	int isMatch = 1;
	for(players=0;players<=totalPlayers && isMatch != 0;players++)
	{
	       isMatch = strcmp(player[players].name,endBatter);
	}
			
	if(isMatch == 0)
	{
	       cout << player[players].name << "'s average is: "
	               << player[players].avg
	               << endl;
	}
	if(isMatch != 0)
	{
	        cout << "You did not enter a valid player's name. \n"
	               << endl;
	}

	char yesNo[4];
	bool validData = false;
	while(!validData)
	{
                    cout << "Would you like to enter another player's name? Y/N"
	            << endl;
	    cin.getline(yesNo,4);

	    if(strcmp(yesNo,"y") == 0 || strcmp(yesNo,"Y") == 0 || strcmp(yesNo,"n") == 0 || strcmp(yesNo,"N") == 0)
	   {
                       validDate = true
	   }
	   else
	   {
                         cout << "You did not enter a valid response. \n"
		 << endl;
	    }
	}
   }
   return 0;
}

Again, thank you for the help.

-D

See invisal's post # 2 regarding comparing strings. In particular, C-Style strings behave differently from C++-style strings when comparing with ==. You are using C-Style strings (char arrays). When you do that, the == operator compares the memory locations of the strings, not the contents of the strings. When in doubt, use "compare" and "strcmp" rather than ==. Here is an example. Notice that you may get results that you aren't expecting:

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

int main ()
{
    char cStyleString1[] = "A";
    char cStyleString2[] = "A";
    string cPlusStyleString1 = "B";
    string cPlusStyleString2 = "B";
    
    if (cStyleString1 == cStyleString2)
        cout << "Test 1 : Strings are the same\n";
    else
        cout << "Test 1 : Strings are not the same\n";
        
    if (strcmp (cStyleString1, cStyleString2) == 0)
        cout << "Test 2 : Strings are the same\n";
    else
        cout << "Test 2 : Strings are not the same\n";
        
    if (cStyleString1 == "A")
        cout << "Test 3 : String 1 is A\n";
    else
        cout << "Test 3 : String 1 is not A\n";
        
    if (cPlusStyleString1 == cPlusStyleString2)
        cout << "Test 4 : Strings are the same\n";
    else
        cout << "Test 4 : Strings are not the same\n";
        
    if (cPlusStyleString1.compare (cPlusStyleString2) == 0)
        cout << "Test 5 : Strings are the same\n";
    else
        cout << "Test 5 : Strings are not the same\n";
        
    if (cPlusStyleString1 == "B")
        cout << "Test 6 : String 1 is B\n";
    else
        cout << "Test 6 : String 1 is not B\n";
        
    cin.get ();
    return 0;   
}

Consider using C++ style strings rather than C Style strings. Each work just fine, but in some ways C-Style strings are more tricky.

http://www.cplusplus.com/reference/string/string/

So line 65 in your program is going to probably cause you problems because:

1) You are comparing the contents using == with a C-Style string.
2) You don't define yesNo until line 90. Define it BEFORE you use it.

Also, look at toupper and tolower from cctype:

http://www.cplusplus.com/reference/clibrary/cctype/toupper/
http://www.cplusplus.com/reference/clibrary/cctype/tolower/

It converts characters to upper or lower case, so you don't have to worry about comparing to both 'Y' and 'y'. But that can be for a future program. It's an option to consider so you don't have to make as many comparisons.

See invisal's post # 2 regarding comparing strings. In particular, C-Style strings behave differently from C++-style strings when comparing with ==. You are using C-Style strings (char arrays). When you do that, the == operator compares the memory locations of the strings, not the contents of the strings. When in doubt, use "compare" and "strcmp" rather than ==. Here is an example. Notice that you may get results that you aren't expecting:. . .

Consider using C++ style strings rather than C Style strings. Each work just fine, but in some ways C-Style strings are more tricky.

http://www.cplusplus.com/reference/string/string/

So line 65 in your program is going to probably cause you problems because:

1) You are comparing the contents using == with a C-Style string.
2) You don't define yesNo until line 90. Define it BEFORE you use it.

Also, look at toupper and tolower from cctype:

http://www.cplusplus.com/reference/clibrary/cctype/toupper/
http://www.cplusplus.com/reference/clibrary/cctype/tolower/

It converts characters to upper or lower case, so you don't have to worry about comparing to both 'Y' and 'y'. But that can be for a future program. It's an option to consider so you don't have to make as many comparisons.

Great catch with the YesNo being introduced after it is already referred to. That probably would have driven me nuts for a long time.

For some reason, the book that I've been learning C++ from hasn't even introduced C++ strings let alone explained any difference from C strings. So if I include <string> and change all of my char arrays that I used as strings to variable type string it would essentially be the same thing? For instance:

string yesNo = "y"

//instead of

char yesNo[4] = "y"

Also, with your mention of toupper, would I use it within my comparisons? I just read the info from the link that you gave me, but I'm not entirely sure how to put it to practical use in this particular scenario...

-D

So if I include <string> and change all of my char arrays that I used as strings to variable type string it would essentially be the same thing? For instance:

string yesNo = "y"

//instead of

char yesNo[4] = "y"

Right. Just make sure to do it everywhere or nowhere. Mixing C-Style strings and regular strings can cause problems.

Also, with your mention of toupper, would I use it within my comparisons? I just read the info from the link that you gave me, but I'm not entirely sure how to put it to practical use in this particular scenario...
-D

toupper and tolower work on characters rather than strings. Right now you have yesNo as a string (or a C-String), so if you are checking for "Y" or "y", look at the first character of the string. Remember to #include <cctype>

string yesNo = "Y";
bool validData = false;
while (!validData)
{
    cout << "Enter Y or y for yes, N or n for no : ";
    cin >> yesNo;
    if (toupper (yesNo[0] == 'Y') // note single quotes, not double quotes
    {
        cout << "You entered yes.\n";
        validData = true;
    }
    else if (toupper (yesNo[0]) == 'N')  // note single quotes, not double quotes
    {
        cout << "You entered no.\n";
        validData = true;
    }
    else
        cout << "Error: you entered neither yes or no.  Try again\n";
}

cout << "Done with loop.  Valid data has been entered.\n";

Might want to hold off on this till the next program, but it's something to think about.

Hey,

So I finally got around to fixing up the code, but I'm getting some major compiling errors. Here is the code as it stands now:

#include <iostream>
#include <cstring>
#include <string>
#include <locale>

using namespace std;

void displayInstructions(void)
{
	cout << "This program is created to allow you to enter \n"
		 << "up to 5 baseball players' names and averages and then \n"
		 << "enter a player's name to receive their average. \n"
		 << endl;

	cout << "To stop entering names, enter the word 'end' when asked \n"
		 << "for the player's name."
		 << endl;
}

int main()
{
	displayInstructions();

	class ballPlayer{
	public:
		string name;
		int avg;
					 };

	int numPlayer;
	int totalPlayers=0;
	ballPlayer player[5];
	
	for(numPlayer=0;numPlayer<=4;numPlayer++)
	{
		cout << "Please enter a player's name:"
			 << endl;
		cin.getline(player[numPlayer].name,30);

		while(strcmp(player[0].name,"end") == 0)
		{
			cout << "Please enter at least one batter's name."
				 << endl;
			cin.getline(player[numPlayer].name,30);
		}
		if(strcmp(player[numPlayer].name,"end") == 0 && player != 0)
		{
			break;
		}

		cout << "Please enter this player's average:"
			 << endl;
		cin >> player[numPlayer].avg;

		while(player[numPlayer].avg > 1000)
		{
			cout << "This is not a valid batter's average. \n"
				 << endl;
			cout << "Please enter a valid bater's average:"
				 << endl;
			cin >> player[numPlayer].avg;
		}
		totalPlayers++;
	}

	string endBatter;
	string yesNo = "y";
	while(yesNo == "y" || yesNo == "Y")
	{
		cout << "Enter the player's name to get their average:"
			 << endl;
		cin.getline(endbatter,30);

		int isMatch = 1;
		for(numPlayer=0;numPlayer<=totalPlayers && isMatch != 0;numPlayer++)
		{
			isMatch = strcmp(player[numPlayer].name,endBatter);
		}
		if(isMatch == 0)
		{
			cout << player[numPlayer].name << "'s average is: "
				 << player[numPlayer].avg << endl;
		}
		if(isMatch != 0)
		{
			cout << "You did not enter a valid player's name. /n"
				 << endl;
		}

		bool validDate=false
		while(!validDate)
		{
			cout << "Would you like to enter another player's name? Y/N"
				 << endl;
			cin.getline(yesNo,4);

			if(strcmp(yesNo,"y") == 0 || strcmp(yesNo,"Y") == 0 || strcmp(yesNo,"n") == 0 || strcmp(yesNo,"n"( == 0))
			{
				validDate=true;
			}
			else
			{
				cout << "You did not enter Y or N.  Please reenter your response."
					 << endl;
			}
		}
	}
	return 0;
}

This is the error readout that I am getting:

"1>------ Rebuild All started: Project: BaseballPlayers, Configuration: Debug Win32 ------
1>Deleting intermediate and output files for project 'BaseballPlayers', configuration 'Debug|Win32'
1>Compiling...
1>SourceCode.cpp
1>c:\documents and settings\__________\my documents\visual studio 2008\projects\baseballplayers\baseballplayers\sourcecode.cpp(38) : error C2664: 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::getline(_Elem *,std::streamsize)' : cannot convert parameter 1 from 'std::string' to 'char *'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>c:\documents and settings\___________\my documents\visual studio 2008\projects\baseballplayers\baseballplayers\sourcecode.cpp(40) : error C2664: 'strcmp' : cannot convert parameter 1 from 'std::string' to 'const char *'
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>c:\documents and settings\___________\my documents\visual studio 2008\projects\baseballplayers\baseballplayers\sourcecode.cpp(40) : fatal error C1903: unable to recover from previous error(s); stopping compilation
1>Build log was saved at "file://c:\Documents and Settings\_________\My Documents\Visual Studio 2008\Projects\BaseballPlayers\BaseballPlayers\Debug\BuildLog.htm"
1>BaseballPlayers - 3 error(s), 0 warning(s)
========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========

I'm not entirely sure what the error means, but according the the line reading, it had to do with using strcmp() on the string name. Can you guys help point me in the right direction?

Thanks,
D

That's the potential messiness I was referring to regarding C-Strings and C++-strings and mixing them. The syntax for each is close, but not quite the same. It can be annoying when you're starting out and aren't familiar with it, but you'll get the hang of it. Here's some revised code. I change the strcmp calls to compare calls, along with the correct syntax. Ditto with getline. The syntax is slightly different. One more problem. You are mixing getline with >> when you are inputting data. That can be problematic. When you do that, sometimes questions get skipped so you'll see a prompt for a question, but the program won't wait for the answer. The reasons for this are a bit technical, so don't worry if you get confused. The short answer/solution is this: if a question is skipped, chances are you are mixing formatted and unformatted input methods (i.e. getline and >>) and you need to flush the input stream. Here's a good thread on the subject. The author explains the problem, gives examples, gives a solution, and tells you when to stop reading if you aren't interested in the nitty-gritty. It comes up all the time and is thus pinned to the top of the C++ forum here.

http://www.daniweb.com/forums/thread90228.html

So if questions get skipped, clear the input stream using the info from this thread. Here's your revised code. I finished changing the char* stuff to string, plus added a semicolon here and there, I think. Stuff like that. It's still your code basically and it still has the buffer problems (and possibly other problems. Test it). Please report back. I'd be interested in hearing whether you were able to complete the program and seeing the final product.

#include <iostream>
#include <cstring>
#include <string>
#include <locale>

using namespace std;

void displayInstructions(void)
{
	cout << "This program is created to allow you to enter \n"
		 << "up to 5 baseball players' names and averages and then \n"
		 << "enter a player's name to receive their average. \n"
		 << endl;

	cout << "To stop entering names, enter the word 'end' when asked \n"
		 << "for the player's name."
		 << endl;
}

int main()
{
	displayInstructions();

	class ballPlayer{
	public:
		string name;
		int avg;
					 };

	int numPlayer;
	int totalPlayers=0;
	ballPlayer player[5];
	
	for(numPlayer=0;numPlayer<=4;numPlayer++)
	{
		cout << "Please enter a player's name:"
			 << endl;
		getline(cin, player[numPlayer].name, '\n');

		while(player[0].name.compare ("end") == 0)
		{
			cout << "Please enter at least one batter's name."
				 << endl;
			getline(cin, player[numPlayer].name);
		}
		if(player[numPlayer].name.compare ("end") == 0 && player != 0)
		{
			break;
		}

		cout << "Please enter this player's average:"
			 << endl;
		cin >> player[numPlayer].avg;

		while(player[numPlayer].avg > 1000)
		{
			cout << "This is not a valid batter's average. \n"
				 << endl;
			cout << "Please enter a valid bater's average:"
				 << endl;
			cin >> player[numPlayer].avg;
		}
		totalPlayers++;
	}

	string endBatter;
	string yesNo = "y";
	while(yesNo == "y" || yesNo == "Y")
	{
		cout << "Enter the player's name to get their average:"
			 << endl;
		getline(cin, endBatter, '\n');

		int isMatch = 1;
		for(numPlayer=0;numPlayer<=totalPlayers && isMatch != 0;numPlayer++)
		{
			isMatch = player[numPlayer].name.compare (endBatter);
		}
		if(isMatch == 0)
		{
			cout << player[numPlayer].name << "'s average is: "
				 << player[numPlayer].avg << endl;
		}
		if(isMatch != 0)
		{
			cout << "You did not enter a valid player's name. /n"
				 << endl;
		}

		bool validData=false;
		while(!validData)
		{
			cout << "Would you like to enter another player's name? Y/N"
				 << endl;
			getline(cin, yesNo);

			if(yesNo.compare ("Y") == 0 || yesNo.compare ("y") == 0 || yesNo.compare ("N") == 0 || yesNo.compare ("n") == 0)
			{
				validData=true;
			}
			else
			{
				cout << "You did not enter Y or N.  Please reenter your response."
					 << endl;
			}
		}
	}
	return 0;
}

Edit: Line 86. Just noticed this. The newline character is '\n', not '/n'. You have '/n'. Change it to '\n'.

I looked through the revised code and I see the syntax changes that you made. I wasn't aware that it was better to use getline(cin,...,...) insteat of cin.getline(....). I'm also going to assume that cin >>, based on your selective use of it, is really only appropriate to use if the user is entering something other than a string or char.

I read through the thread that you linked to and it has some great information. As I understood it (and i'm not 100% sure I understood correctly), if you use any form of cin >> or cin.xxx (unformatted inputs), and you're going to be following it with a formatted input you will need flush the input stream by using:

#include <istream>

void ignore_line ( std::istream& in )
{
  char ch;

  while ( in.get ( ch ) && ch != '\n' )
    ;
}

Am I correct in those assumptions? I really with the book that I started learning C++ from (C++ for dummies) had the information that I'm getting here.

I really appreciate all of your help with this.

-D

I looked through the revised code and I see the syntax changes that you made. I wasn't aware that it was better to use getline(cin,...,...) insteat of cin.getline(....). I'm also going to assume that cin >>, based on your selective use of it, is really only appropriate to use if the user is entering something other than a string or char.

I read through the thread that you linked to and it has some great information. As I understood it (and i'm not 100% sure I understood correctly), if you use any form of cin >> or cin.xxx (unformatted inputs), and you're going to be following it with a formatted input you will need flush the input stream by using:

#include <istream>

void ignore_line ( std::istream& in )
{
  char ch;

  while ( in.get ( ch ) && ch != '\n' )
    ;
}

Am I correct in those assumptions? I really with the book that I started learning C++ from (C++ for dummies) had the information that I'm getting here.

I really appreciate all of your help with this.

-D

As to the stream clearing, if you read a little lower, you can do it like this:

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

In your case, your stream is cin, so replace "in" with "cin" above.

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

Stick this line after your cin statements in your program. Narue has it as a function that you call. That works too, but you can avoid that and stick the line above after all of your cin statements and things should work fine.

Regarding getline, I don't think it's a matter of one being preferable. I think you simply cannot use cin.getline with a string, period. At least if you can, I don't know how.

Use this with C-strings:

http://www.cplusplus.com/reference/iostream/istream/getline/

Use this with strings:

http://www.cplusplus.com/reference/string/getline/

The function specification tells you the types that the functions require.

Great! Thank you for this help. I will give the program a go tonight when I get home and I'll report back with the results.

-D

I'm also going to assume that cin >>, based on your selective use of it, is really only appropriate to use if the user is entering something other than a string or char.

Using cin >> is fine for all sorts of data, including characters, strings, integers, doubles, floats, etc. You just need to know the pros and cons and issues involved. >> ignores and is automatically delimited by white space (line returns, spaces, tabs). getline and get aren't. Hence the cin >> leaves the '\n' in the stream, then getline grabs that '\n' and moves on, thinking it is done. You clear that '\n' from the stream using ignore to avoid that and to force getline to wait for the user to type in another '\n'. getline is great for getting a whole line of data into a string, which may include spaces (for example, first and last name). So it's a matter of using the right tool at the right time for the right job in the right way more than "never use this for this, always use that for that".

Using cin >> is fine for all sorts of data, including characters, strings, integers, doubles, floats, etc. You just need to know the pros and cons and issues involved. >> ignores and is automatically delimited by white space (line returns, spaces, tabs). getline and get aren't. Hence the cin >> leaves the '\n' in the stream, then getline grabs that '\n' and moves on, thinking it is done. You clear that '\n' from the stream using ignore to avoid that and to force getline to wait for the user to type in another '\n'. getline is great for getting a whole line of data into a string, which may include spaces (for example, first and last name). So it's a matter of using the right tool at the right time for the right job in the right way more than "never use this for this, always use that for that".

That makes much more sense now. I guess my only remaining question pertaining to that is: what exactly is the difference between cin.getline(xxx) and getline(cin,xxx). I noticed that you changed that in the code and was wondering why.

Also, i noticed that you changed all of the strcmp() to string.compare(). Do the two act in the same manner (returning 0 if they match)?

-D

That makes much more sense now. I guess my only remaining question pertaining to that is: what exactly is the difference between cin.getline(xxx) and getline(cin,xxx). I noticed that you changed that in the code and was wondering why.

Also, i noticed that you changed all of the strcmp() to string.compare(). Do the two act in the same manner (returning 0 if they match)?

-D

http://www.cplusplus.com

This website has all the libraries and specifications. One of your first tasks as a programmer is to look up the specification of a function in the documentation. I linked the relevant links within the website for the two getline functions. The specification for the non-string getline is this:

istream& getline (char* s, streamsize n );
istream& getline (char* s, streamsize n, char delim );

Neither of these take a string as an argument, so you can't use them with strings. Both have an argument for the maximum number of characters to read in. That's because there is always a risk that you read in data beyond your storage capacities. The n parameter above is for you, the programmer, to fill in so that is avoided.

Here's the string getline spec:

istream& getline ( istream& is, string& str, char delim );
istream& getline ( istream& is, string& str );

This one takes a string as a parameter, not a char*, so you can't use a char*. There's no parameter for the maximum number of characters to read in, because that's not an issue with strings. Hence, two different functions because the needs and assumptions are different for the two different data types (C-strings and C++-strings). Strings handle a lot of stuff for you that you yourself have to handle as the programmer.

When you get a compiler error, always go to the documentation for that function and make sure your function call matches the spec.

Ditto for compare and strcmp. Different libraries, different data types, same basic usage.

http://www.cplusplus.com/reference/clibrary/cstring/strcmp/

int strcmp ( const char * str1, const char * str2 );

Takes char* arguments, so you can't use a string.

http://www.cplusplus.com/reference/string/string/compare/

Compare is a little more versatile. You can compare a string to a char* OR another string.

int compare ( const string& str ) const;
int compare ( const char* s ) const;
int compare ( size_t pos1, size_t n1, const string& str ) const;
int compare ( size_t pos1, size_t n1, const char* s) const;
int compare ( size_t pos1, size_t n1, const string& str, size_t pos2, size_t n2 ) const;
int compare ( size_t pos1, size_t n1, const char* s, size_t n2) const;

I have finally gotten a working code that does exactly what I set out to do. While it isn't the best written code ever, it compiles, and runs smoothly. Here is the final code:

#include <iostream>
#include <cstring>
#include <string>

using namespace std;

void displayInstructions(void)
{
	cout << "This program is created to allow you to enter \n"
		 << "up to 5 baseball players' names and averages and then \n"
		 << "enter a player's name to receive their average. \n"
		 << endl;

	cout << "To stop entering names, enter the word 'end' when asked \n"
		 << "for the player's name."
		 << endl;
}

void ignore_line ( std::istream& in )
{
char ch;
while ( in.get ( ch ) && ch != '\n' );
}
int main()
{
	displayInstructions();

	class ballPlayer{
	public:
		string name;
		int avg;
					 };

	int numPlayer;
	int totalPlayers=0;
	ballPlayer player[5];
	
	for(numPlayer=0;numPlayer<=4;numPlayer++)
	{
		cout << "\nPlease enter a player's name:"
			 << endl;
		getline(cin,player[numPlayer].name);

		while(player[0].name.compare("end") == 0)
		{
			cout << "\nPlease enter at least one batter's name."
				 << endl;
			getline(cin,player[numPlayer].name);
		}
		if(numPlayer>1)
		{
			for(int i=0;i<=numPlayer;i++)
			{
				int count=0;
				int sameName = player[numPlayer].name.compare(player[count].name);
			
				if(sameName == 0)
				{
					cout << "You have already entered that name. \n"
						 << endl;
					cout << "Please enter a player's name:"
						 << endl;
					getline(cin,player[numPlayer].name);
				}
				count++;
			}
		}
		if(player[numPlayer].name.compare("end") == 0 && numPlayer != 0)
		{
			break;
		}

		cout << "\nPlease enter this player's average:"
			 << endl;
		cin >> player[numPlayer].avg;
		ignore_line(cin);

		while(player[numPlayer].avg > 1000)
		{
			cout << "\nThis is not a valid batter's average. \n"
				 << endl;
			cout << "Please enter a valid bater's average:"
				 << endl;
			cin >> player[numPlayer].avg;
			ignore_line(cin);
		}
		totalPlayers++;
	}

	string endBatter;
	string yesNo = "y";
	while(yesNo == "y" || yesNo == "Y")
	{
		cout << "\nEnter the player's name to get their average:"
			 << endl;
		getline(cin,endBatter);

		int isMatch = 1;
		for(numPlayer=0;numPlayer<=totalPlayers-1;numPlayer++)
		{
			isMatch = endBatter.compare(player[numPlayer].name);
			if(isMatch == 0)
			{
				break;
			}
		}
		if(isMatch == 0)
		{
			cout << "\n" << player[numPlayer].name << "'s average is: "
				 << player[numPlayer].avg << endl;
		}	
		if(isMatch != 0)
		{
			cout << "\nYou did not enter a valid player's name. \n"
				 << endl;
		}
		
		bool validDate=false;
		while(!validDate)
		{
			cout << "\nWould you like to enter another player's name? Y/N"
				 << endl;
			getline(cin,yesNo);

			if(yesNo.compare("y") == 0 || yesNo.compare("Y") == 0 || yesNo.compare("n") == 0 || yesNo.compare("n") == 0)
			{
				validDate=true;
			}
			else
			{
				cout << "\nYou did not enter Y or N.  Please reenter your response."
					 << endl;
			}
		}
	}
	return 0;
}

Thanks for all of the help. Now it's on to find a new project to practice these skills further.

-D

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