Reply
Thread Tools
bandora's Avatar
Posts: 1,338 | Thanked: 1,055 times | Joined on Oct 2009 @ California, USA / Jordan
#1
Hey guys,

In the past you guys have been extremely generous and helpful, not to mention very informative! And that's the reason why I keep on asking you guys for help! So I want to thank you guys in advance for your help!

Ok onto the problem... I am creating a program for my C++ class that asks for a movie name and a bunch of ratings twice.. Then displays the average rating for each movie.. I got the code to work but with one small issue.. It only takes the first string from the cin.. So like if someone enters "American Pie" for example it will only read it as American... Now I managed to go around the issue and by using a small while loop and that worked for the first movie but it messed up the second cin...

Here's the code so you can see what I'm talking about:

Code:
#include <iostream>
#include <string>

using namespace std;

class Movie 
{
private:
	string movieName, MPAARating; 
	int numRate[5]; 

public:
	Movie(string movie)
	{
		movieName = movie;
		MPAARating=5; 
		numRate[0]=0; 
		numRate[1]=0; 
		numRate[2]=0; 
		numRate[3]=0; 
		numRate[4]=0; 
	}

	Movie() // Default Constructor
	{
		MPAARating=5; 
		numRate[0]=0; 
		numRate[1]=0; 
		numRate[2]=0; 
		numRate[3]=0; 
		numRate[4]=0; 
	} 
	
	string getMovieName() 
	{ 
		return movieName;
	} 
	
	void setMovieName (string str)
	{
		movieName = str;
	}
	
	string getMPAARating()
	{ 
		return MPAARating;
	} 
	
	void setMPAARating (string str)
	{ 
		MPAARating = str; 
	} 
	
	void addRating(int num)
	{
		int i = num;
		if( num>0 && num <= 5)
		{
			this->numRate[i-1]++;
		} 
		
		else
		{ 
			cout <<"Number out of range."<<endl;
		}
	} 
	
	double getAverage()
	{
		double num = numRate[0]+numRate[1]+numRate[2]+numRate[3]+numRate[4];
		double denom = 5.0;
		double result = num/denom;

		return result; 
	}
};
	
int main()
{	
	string setMovieName;
	int rating;
	char again = 'y';

	cout << "Insert a movie name: ";
	char c = 0;
	while(c !='\n')
	{
		c = cin.get();
		setMovieName.push_back(c);
	}
	
	setMovieName.erase(setMovieName.end() - 1); //setMovieName.erase(setMovieName.begin() + setMovieName.size() - 1);

	Movie obj1(setMovieName);

	while (again == 'y' || again == 'Y')
	{
		cout << "Add the rating of the movie (1-5): ";
		cin >> rating; 
		obj1.addRating(rating);

		cout << "Add more ratings? (y/n): ";
		cin >> again;
	}

	cout << "\nInsert a movie name: "; 
	c = 0;
	while(c !='\n')             // PROGRAM TOTALLY SKIPS THIS WHILE LOOP (checked by debugging)..
	{
		c = cin.get();
		setMovieName.push_back(c);
	}
	
	setMovieName.erase(setMovieName.end() - 1);

	Movie obj2(setMovieName);

	again = 'y';

	while (again == 'y' || again == 'Y')
	{
		cout << "Add the rating of the movie (1-5): ";
		cin >> rating; 
		obj2.addRating(rating);

		cout << "Add more ratings? (y/n): ";
		cin >> again;
	}
		
	double ave1 = obj1.getAverage();
	double ave2 = obj2.getAverage();

	cout <<"\nAverage rating for "<<  obj1.getMovieName() <<": " <<ave1<<endl;
	cout <<"Average rating for "<< obj2.getMovieName() <<": " <<ave2<<endl; 

	system("pause");
	return 0;
}
Any help would be GREATLY appreciated!

EDIT: I tried different things like using a different char (d instead of c) for the second movie.. I tried to even make another contructor called setMovieName2... It just does the same..

This is what's happening when I run the program:
__________________
FarahFa.com

Last edited by bandora; 2013-11-26 at 06:36.
 

The Following User Says Thank You to bandora For This Useful Post:
nicolai's Avatar
Posts: 1,637 | Thanked: 4,424 times | Joined on Apr 2009 @ Germany
#2
try the getline function:
http://en.cppreference.com/w/cpp/str...string/getline

std::string moviename
std::getline(std::cin, moviename);
 

The Following 3 Users Say Thank You to nicolai For This Useful Post:
bandora's Avatar
Posts: 1,338 | Thanked: 1,055 times | Joined on Oct 2009 @ California, USA / Jordan
#3
I should've mentioned that I've tried doing that and it didn't work either.. :/

I actually tried doing that before going for that small while loop... :/
__________________
FarahFa.com

Last edited by bandora; 2013-11-26 at 07:32.
 
pichlo's Avatar
Posts: 6,445 | Thanked: 20,981 times | Joined on Sep 2012 @ UK
#4
Your main problem is that your cin.get(); on line 110 reads the '\n' that was left over in the input buffer after cin >> again; on line 103. You can try replacing the loop around the line 110 with something like
Code:
    c = cin.get();
    if (c != '\n')
    {
        cin.unget();
    }
    while((c = cin.get()) != '\n')
    {
        setMovieName.push_back(c);
    }
Having done that, you can then refactor the whole thing using getline() instead of spelling out the loops manually.

I am also a bit perplexed by the way you calculate the average rating, but I leave that bit to your tutor

Lastly, your system("pause"); is not portable. But you probably already know that.
 

The Following 4 Users Say Thank You to pichlo For This Useful Post:
humble's Avatar
Posts: 355 | Thanked: 395 times | Joined on Dec 2009 @ USA
#5
@bandora, I took a look at your code, and i say.. make a function out of your loops

ex. loop() and run that twice(or evenmore) and incorporate some kind of database to get the data generated.
__________________
Would you like to Donate?

My"Current Project(s)":
[Resurrecting] DON
 

The Following 2 Users Say Thank You to humble For This Useful Post:
pichlo's Avatar
Posts: 6,445 | Thanked: 20,981 times | Joined on Sep 2012 @ UK
#6
Incidentally, for line-based input like yours, the best practice is to always read a line at a time using standard functions like getline() that consume the terminating '\n', then parsing the string, as opposed to parsing the standard input directly. That way you not only avoid surprises of the "'\n' left over in the buffer" kind, but also get extra robustness for cases when the user replies with "3, you silly old program" to queries requesting only a number (hint: cin << number will only swallow the 3, the rest including the comma will be left in the input buffer for the next cin operation to read).
 

The Following 3 Users Say Thank You to pichlo For This Useful Post:
bandora's Avatar
Posts: 1,338 | Thanked: 1,055 times | Joined on Oct 2009 @ California, USA / Jordan
#7
Originally Posted by pichlo View Post
...
Thank you so much for taking the time to help me out! I have added that to my code and that particular problem got fixed, but now I am getting a new problem (I think due to the input buffer not getting cleared?) Please look at EDIT2..

Here's the updated code:

Code:
#include <iostream>
#include <string>

using namespace std;

class Movie 
{
private:
	string movieName, MPAARating; 
	int numRate[5]; 

public:
	Movie(string movie)
	{
		movieName = movie;
		MPAARating=5; 
		numRate[0]=0; 
		numRate[1]=0; 
		numRate[2]=0; 
		numRate[3]=0; 
		numRate[4]=0; 
	}

	Movie() // Default Constructor
	{
		MPAARating=5; 
		numRate[0]=0; 
		numRate[1]=0; 
		numRate[2]=0; 
		numRate[3]=0; 
		numRate[4]=0; 
	} 
	
	string getMovieName() 
	{ 
		return movieName;
	} 
	
	void setMovieName(string str)
	{
		movieName = str;
	}
	
	string getMPAARating()
	{ 
		return MPAARating;
	} 
	
	void setMPAARating(string str)
	{ 
		MPAARating = str; 
	} 
	
	void addRating(int num)
	{
		int i = num;
		if( num>0 && num <= 5)
		{
			this->numRate[i-1]++;
		} 
		
		else
		{ 
			cout <<"Number out of range."<<endl;
		}
	} 
	
	double getAverage()
	{
		double num = numRate[0]+numRate[1]+numRate[2]+numRate[3]+numRate[4];
		double denom = 5.0;
		double result = num/denom;

		return result; 
	}
};
	
int main()
{	
	string setMovieName;
	int rating;
	char again = 'y';

	cout << "Insert a movie name: ";
	char c = 0;
	c = cin.get();
    if (c != '\n')
    {
        cin.unget();
    }
    while((c = cin.get()) != '\n')
    {
        setMovieName.push_back(c);
    }

	Movie obj1(setMovieName);
	//char c = 0;
	//while(c !='\n')
	//{
	//	c = cin.get();
	//	setMovieName.push_back(c);
	//}
	//
	//setMovieName.erase(setMovieName.end() - 1); //setMovieName.erase(setMovieName.begin() + setMovieName.size() - 1);


	while (again == 'y' || again == 'Y')
	{
		cout << "Add the rating of the movie (1-5): ";
		cin >> rating; 
		obj1.addRating(rating);

		cout << "Add more ratings? (y/n): ";
		cin >> again;
	}

	cout << "\nInsert a movie name: ";
	c = cin.get();
    if (c != '\n')
    {
        cin.unget();
    }
    while((c = cin.get()) != '\n')
    {
        setMovieName.push_back(c);
    }

	Movie obj2(setMovieName);

	//c = 0;
	//while(c !='\n')
	//{
	//	c = cin.get();
	//	setMovieName.push_back(c);
	//}
	//
	//setMovieName.erase(setMovieName.end() - 1);

	again = 'y';

	while (again == 'y' || again == 'Y')
	{
		cout << "Add the rating of the movie (1-5): ";
		cin >> rating; 
		obj2.addRating(rating);

		cout << "Add more ratings? (y/n): ";
		cin >> again;
	}
		
	double ave1 = obj1.getAverage();
	double ave2 = obj2.getAverage();

	cout <<"\nAverage rating for "<<  obj1.getMovieName() <<": " <<ave1<<endl;
	cout <<"Average rating for "<< obj2.getMovieName() <<": " <<ave2<<endl; 

	system("pause");
	return 0;
}
And here's the output:



I tried putting cin.clear(); after the first cin but that didn't do anything..

Also, would you care to elaborate what you meant about the average calculations please.. Are my calculations wrong? :/

Oh and also yes the system("pause"); is there only temporarily, only because when I start it without debugging the program would quit immediately after showing the averages!

Also, @Humble, I really do appreciate your input, however I didn't want to go over the top by doing all that for this program because it's only a homework problem, so honestly I was just being lazy in regards to that! haha

EDIT: Should I create another constructor with the name setMovieName2? To store the second movie name to that? Because right now it's just adding the values for the second movie onto the same setMovieName... (Checked that by debugging)..

EDIT2: Creating another constructor named setMovieName2 worked!!! So now my question is.. Is the calculation for the average wrong?? I really would like to know because I honestly thought that there's nothing wrong with the calculations and now I am worried that I did it wrong lol..
__________________
FarahFa.com

Last edited by bandora; 2013-11-26 at 20:31.
 
pichlo's Avatar
Posts: 6,445 | Thanked: 20,981 times | Joined on Sep 2012 @ UK
#8
Your movie names get concatenated. Why do you think this is? What do you use to contain the names and how do you initialize it? (Hinr: you use a single string and you get the name into it by appending one character at a time.) What happens when you enter a new name?

Regarding your average ratings, I find I do not understand how you calculate them. In your own example, you rated American Pie as 4 and Thor as 5. You gave each of them just one rating, so I would expect the averages to be 4 and 5, respectively. Why are they 0.2? Maybe it's as intended, but it's not what I would expect, which is why I said I'd leave it to your tutor.

Humble is right, your code layout is a bit awkward. There is a lot of repetition. In general, if you find yourself writing the same code twice, you are doing something wrong. Even as few as two copies call for separating the common code into a function.

Maybe I'm wrong. I do not know what your assignemt says exactly, but the way I would have approached is something like this (in pseudocode)...
Code:
loop
   read_movie_name

   loop
      read_rating
      ask "rate again?"
      if (answer_was_no)
         break loop
   end loop

   calculate_averages

   ask "another movie?"
   if (answer_was_no)
      break loop
end loop
To calculate averages, I would divide the sum of all ratings by their number.
 

The Following User Says Thank You to pichlo For This Useful Post:
bandora's Avatar
Posts: 1,338 | Thanked: 1,055 times | Joined on Oct 2009 @ California, USA / Jordan
#9
Originally Posted by pichlo View Post
...
Thank you for the input! That's very helpful for future programs, but in this particular homework, I don't need more than 2 movies that's why I just did it this way..

Btw, I see what you mean about the average.. But if I am not asking for much could you give me a hint on how to do it? Like how do I get the program to count how many times I've entered a rating and divide by that number...

Should I do a for loop in the main function when I enter the ratings? But if I do how do I return it to the getAverage() constructor..? That's not even possible right?

Or do I change the void addRating(int num) constructor to a int addRating(int num) and return a value?

Hmm.. I am a bit confused not to mention my brain is fried lol.. Too many homework due at the same time! D:
__________________
FarahFa.com
 
pichlo's Avatar
Posts: 6,445 | Thanked: 20,981 times | Joined on Sep 2012 @ UK
#10
Doing something even just twice is good enough a reason to make it a loop. 2 is a special case of N. If your assignment calls explicitly for doing it twice, unlikely as it sounds, then I would still write it as a loop that runs twice.

But enough of that, now to your averages. What is an average? A sum of all inputs divided by their number. Your assignment does not require to remember all the ratings, only the average. So you need just three variables. One temporary for reading the input, one for holding the sum of the inputs and one for holding their number. So get rid of MPAARating (it is not used anywhere) and replace numRate[5] with just two numbers, one for the sum and one for the number. Initialize both to 0, then each time the user enters a rating, add the rating to the sum and add 1 to the number. At the end, divide the sum with the number.
 

The Following User Says Thank You to pichlo For This Useful Post:
Reply

Thread Tools

 
Forum Jump


All times are GMT. The time now is 17:10.