No Names returned in search function - c++

So I cant get my search function to return to the actual title of the movies with the instantiated array with a movie title, director, and actor. I create an array of objects, instantiate it, run a do while loop to get the position, and run a search algorithm to get the title, director, and actor of the movie. But for the life of me I cant get the code to return the actual title, director or actor. It will say the name is in the list, but returns an empty space. I linked a picture below to show the return. When I add a movie to the array it says the movie does not exist in the array.
The movie Class:
class Movies{
private:
// variables
string titleCode;
string directorCode;
string actorCode;
public:
// constructors
Movies() // default constructor, allows no arguments.
{
//titleCode = "Home Movie"; directorCode = "Colin Powers"; actorCode = "Colin Powers";
}
Movies(string t, string d, string a) // constructor
{
titleCode = t; directorCode = d; actorCode = a;
}
// getter
string getTitle() const
{
string title = titleCode;
return title;
}
string getDirector() const
{
string director = directorCode;
return director;
}
string getActors() const
{
string actors = actorCode;
return actors;
}
// setters
void setTitle(string t) // cout/cin were giving random "ambigious" error so i added std:: till they all stopped giving it.
{
std::cout << "Enter the title of the Movie: " << endl;
std::cin >> t;
titleCode = t;
}
void setDirector(string d)
{
std::cout << "Enter the Director of the Movie: " << endl;
std::cin >> d;
directorCode = d;
}
void setActors(string a)
{
std::cout << "Enter the main protagonist: " << endl;
std::cin >> a;
actorCode = a;
}};
Movies Array:
Movies moviesArr[ARR_SIZE];
Function prototype for the search function
int searchMovies(const Movies[], int, string);
Instantiated array of objects to search through
Movies hollywood[ARR_SIZE] =
{ // title, director, actor
Movies("Avatar", "James", "James"),
Movies("Terminator", "John", "John"),
Movies("Predator", "Michael", "Michael")
};
Do while to get returned position and names:
do
{
// get the movie title
cout << "Enter the movie title to search: " << endl;
cin >> title;
// search for the object
pos = searchMovies(hollywood, ARR_SIZE, title);
// if pos = -1 the title was not found
if (pos == -1)
cout << "That title does not exit in the list.\n";
else
{
// the object was found so use the get pos to get the description
cout << "The movie: " << moviesArr[pos].getTitle() << " is in the list. " << endl;
cout << "It was Directed by: " << moviesArr[pos].getDirector() << endl;
cout << "It also stars: " << moviesArr[pos].getActors() << endl;
}
// does the user want to look up another movie?
cout << "\nLook up another movie? (Y/N) ";
cin >> doAgain;
} while (doAgain == 'Y' || doAgain == 'y');
Search function to search array:
int searchMovies(const Movies object[], int ARR_SIZE, string value){
int index = 0;
int position = -1;
bool found = false;
while (index < ARR_SIZE && !found)
{
if (object[index].getTitle() == value) // if the title is found
{
found = true; // set the flag.
position = index; // record the values subscript
}
index++; // go to the next element.
}
return position; // return the position or -1;}
output looks like:
Nondescrip return, no names, no director, no title.

This line:
Movies moviesArr[ARR_SIZE];
defines an empty, uninitialized array of Movies. You are searching for a particular Movie title in hollywood, which finds the movie. However, you are then indexing moviesArr:
cout << "The movie: " << moviesArr[pos].getTitle() << " is in the list. " << endl;
which is undefined behaviour (and printed nothing for the title in your case).
Replace that with:
cout << "The movie: " << hollywood[pos].getTitle() << " is in the list. " << endl;

Related

How to input an object in C++?

Hi the code below is a simple class example in C++
#include <iostream>
using namespace std;
class Car { // The class
public: // Access specifier
string brand; // Attribute
string model; // Attribute
int year; // Attribute
Car(string x, string y, int z) { // Constructor with parameters
brand = x;
model = y;
year = z;
}
};
int main() {
// Create Car objects and call the constructor with different values
Car carObj1("BMW", "X5", 1999);
Car carObj2("Ford", "Mustang", 1969);
// Print values
cout << carObj1.brand << " " << carObj1.model << " " << carObj1.year << "\n";
cout << carObj2.brand << " " << carObj2.model << " " << carObj2.year << "\n";
return 0;
}
// W3Schools
As I see it, the way you can define an object is to write it in code like : <ClassName> <ObjectName>
Now my question is : Is there a way to input an object? like cin >> ObjectName;
And after we entered the name of object, we enter the parameters.
Is it possible at all?
You can't enter an object name from the command line, however, you can create a default constructed object and then fill its' properties from the input by overloading operator>>.
class Car {
public:
Car() = default;
// ...
};
std::istream& operator>>(std::istream& in, Car& car) {
in >> car.brand >> car.model >> car.year;
return in;
}
int main() {
Car carObj1;
cout << "Enter a car brand, model, and year: ";
cin >> carObj1;
// ...
}
Yes, There is operator overloading in C++ and you can overload both << and >> operators. Here is an example code:
#include <iostream>
using namespace std;
class Car { // The class
public: // Access specifier
string brand; // Attribute
string model; // Attribute
int year; // Attribute
Car(string x, string y, int z) { // Constructor with parameters
brand = x;
model = y;
year = z;
}
Car() = default;
void Carinput(std::istream& is)
{
is >> brand >> model >> year;
}
void carOutput(std::ostream& os) const
{
os << brand << " " << model << " " << year << std::endl;
}
};
std::istream &operator>>(std::istream &is,Car &car)
{
car.Carinput(is);
return is;
}
std::ostream &operator<<(std::ostream &os,const Car &car)
{
car.carOutput(os);
return os;
}
int main() {
// Create Car objects and call the constructor with different values
Car carObj1("BMW", "X5", 1999);
Car carObj2("Ford", "Mustang", 1969);
// Print values
cout << carObj1.brand << " " << carObj1.model << " " << carObj1.year << "\n";
cout << carObj2.brand << " " << carObj2.model << " " << carObj2.year << "\n";
std::cout << "\n*============================================*\n"
<< std::endl;
std::cout << "Your input:" << std::endl;
Car carObj3;
std::cin >> carObj3;
std::cout << carObj3;
return 0;
}
This is one of the ways of doing it:
#include<iostream>
#include<vector>
class Car
{
public:
Car( const std::string& brand, const std::string& model, int year )
: m_brand( brand ), m_model( model ), m_year( year ) // initialize members like this
{
}
std::string m_brand;
std::string m_model;
int m_year;
};
int main ()
{
std::vector< Car > cars; // use an std::vector to store the objects
std::string brand( "" );
std::string model( "" );
std::string year( "" );
std::cout << "How many cars do you want to add? ";
std::string count( "" );
std::getline( std::cin, count ); // get input as string using std::getline()
int carCount { std::stoi( count ) }; // converts it to type int before
// assigning it to carCount
cars.reserve( carCount ); // reserve some space in vector to avoid
// unnecessary allocations and slowdowns
for ( int idx = 0; idx < carCount; ++idx )
{
std::cout << "Enter the brand name of car number " << idx + 1 << ": ";
std::getline( std::cin, brand );
std::cout << "Enter the model name of car number " << idx + 1 << ": ";
std::getline( std::cin, model );
std::cout << "Enter the production year of car number " << idx + 1 << ": ";
std::getline( std::cin, year );
cars.emplace_back( Car( brand, model, std::stoi( year ) ) ); // push the new Car
} // instance to the
// vector called cars
std::cout << '\n';
for ( int idx = 0; idx < carCount; ++idx )
{
std::cout << "Info for car number " << idx + 1 << ": "
<< cars[ idx ].m_brand << " " << cars[ idx ].m_model << " " << cars[ idx ].m_year << "\n";
}
return 0;
}
Here is the output:
How many cars do you want to add? 2
Enter the brand name of car number 1: Porsche
Enter the model name of car number 1: GT3 RS
Enter the production year of car number 1: 2019
Enter the brand name of car number 2: BMW
Enter the model name of car number 2: M6
Enter the production year of car number 2: 2016
Info for car number 1: Porsche GT3 RS 2019
Info for car number 2: BMW M6 2016
But keep in mind that this class still needs a lot of work like adding member functions (like getters and setters) etc. So this is not how I write classes. I just wanted to keep it simple so you can easily understand the concepts.

c++ program printing out address instead of value

I have a program that takes in information through a struct and puts it into a vector, and I'm trying to print that information out but instead get an address. The structure should hold the values correctly so I think it's either my pointers or the way I'm printing it out.
#include <iostream>
#include <cstring>
#include<vector>
using namespace std;
struct student
{
char* fName;
char* lName;
int id;
float gpa;
};
void add(vector<student*>*);
int main()
{
vector <student*>* list = new vector<student*>();
if (strcmp(cmd,"ADD") == 0)
{
add(list);
}
else if (strcmp(cmd,"PRINT") == 0)
{
for(vector<student*>::iterator i = list->begin(); i != list->end(); i++)
{
cout << *i;
}
cout << "print" << endl;
}
}
void add(vector<student*>* paramlist)
{
student* s = new student();
s->fName = new char[25];
s->lName = new char[25];
cout << "Enter first name" << endl;
cin >> s->fName;
cout << "Enter last name" << endl;
cin >> s->lName;
cout << "Enter id number" << endl;
cin >> s->id;
cout << "Enter GPA" << endl;
cin >> s->gpa;
paramlist->push_back(s);
}
Or it might have something to do with the way I iterate through the vector.
You need to add an operator overload for your struct, to define how the struct should appear when printed. You also need to dereference the pointer as well as the iterator.
// Define how the struct should look when printed.
// This function makes it appear like:
// Name: John Smith, ID: 1235, GPA: 4.0
std::ostream &operator<<(std::ostream &os, const student &val) {
os
<< "Name: " << val.fname << " " << val.lname
<< ", ID: " << val.id
<< ", GPA: " << val.gpa
<< endl;
return os;
}
Then later...
for(vector<student*>::iterator i = list->begin(); i != list->end(); i++)
{
// Dereference twice, once for the iterator, and again for the pointer.
cout << **i << endl;
}
You have to dereference twice **i.
With *i you get the address of vector<student*> element that is student*.
You get student, you need other *.
You may use for (auto i: list) to make your life easier.

how to find a pointer to class based on the parameter of class in STL?

I am creating a project , where i am storing pointer to object in vector(STL).
I want to perform operation based on particular parameter of class . but how to use it i am not getting???
void BankingSystem :: Account_info()
{
// Account * mAccount = vobject.back();
long int ACC_NUMBER;
cout << "Enter AccountNumber : " <<endl;
cin >> ACC_NUMBER;
Account * mAccount = std::find(vobject.begin(),vobject.end(),ACC_NUMBER); //finding based on Account number u can use any parameter
cout << mAccount->Acc_holder.firstName << endl;
cout << mAccount->Acc_holder.aadharNo <<endl;
delete mAccount;
}
std::find (and std::find_if) returns an iterator to the found element (or vobject.end() if it's not found).
You could change it like this:
void BankingSystem :: Account_info()
{
long int ACC_NUMBER;
cout << "Enter AccountNumber : " <<endl;
cin >> ACC_NUMBER;
auto mAccount = std::find_if(vobject.begin(), vobject.end(),
[&ACC_NUMBER](const Account* a) {
// acc_number is maybe called something else in
// your Account class.
return a->acc_number == ACC_NUMBER;
});
// check that you actually found something before printing and erasing:
if(mAccount != vobject.end()) {
auto AccountPtr = *mAccount;
cout << AccountPtr->Acc_holder.firstName << endl;
cout << AccountPtr->Acc_holder.aadharNo <<endl;
vobject.erase(mAccount); // not "delete mAccount;"
delete AccountPtr; // if it's actually is supposed to be deleted
}
}
You should however most probably store Account and not Account* in your vector.

Accessing multiple instances of a class in C++

I am creating a menu for a restaurant that can have 5 dishes of each category. So far I have created a class for meat dishes and I'm able to add up to 5 dishes, each with a unique identifier. What I am having trouble with is accessing the objects after they have been created.
(There will be multiple categories hence why there is a switch statement with only one case so far).
For example, how would I implement a way to change the description of the second dish?
Here is my code so far:
meat.h
class Meat{
private:
int meatNumber;
std::string meatCategory;
std::string meatDescription[MAX_ITEMS];
double meatPrice[MAX_ITEMS];
public:
Meat();
//setter functions
int setMeatNumber();
std::string setMeatDescription();
double setMeatPrice();
//getter functions
int getMeatNumber();
std::string getMeatCategory();
std::string getMeatDescription(int i);
double getMeatPrice(int i);
};
meat.cpp
#include "Meat.h"
//constructor
Meat::Meat() {
meatNumber = 0;
meatCategory = "Meat";
meatDescription[MAX_ITEMS] = "No description written.";
meatPrice[MAX_ITEMS] = 0.0;
}
//setter functions
int Meat::setMeatNumber(){
static int counter = 1;
meatNumber = counter++;
}
std::string Meat::setMeatDescription(){
int i = 0;
std::cout << "Please enter a short description: " << std::endl;
std::cin >> meatDescription[i];
return meatDescription[i];
}
double Meat::setMeatPrice(){
int i = 0;
std::cout << "Please set the price in a 00.00 format: " << std::endl;
std::cout << "£";
while(!(std::cin >> meatPrice[i])){
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Error. Please enter a number: ";
}
return meatPrice[i];
}
//getter functions
int Meat::getMeatNumber() { return meatNumber; }
std::string Meat::getMeatCategory() { return meatCategory; }
std::string Meat::getMeatDescription(int i) {return meatDescription[i]; }
double Meat::getMeatPrice(int i) { return meatPrice[i]; }
main.cpp
#include <iostream>
#include "Meat.h"
int main() {
int choice;
std::cout << "Menu Creation Terminal\n\n" << std::endl;
std::cout << "\t Welcome\nto Wrapid™ Restaurants\n\n" << std::endl;
std::cout << "1. Add Meat Dish\n2. Add Fish Dish\n3. Add Vegetarian Dish\n4. Add Drink\n"
"5. Edit Current Menu\n6. Quit\n\n" << std::endl;
std::cout << "Please select an option: ";
std::cin >> choice;
switch (choice) {
case 1:
{
int option = true;
int count = 0, i;
Meat meatDish;
std::cout << "Meat Dishes" << std::endl;
while (true) {
meatDish.setMeatNumber();
meatDish.setMeatDescription();
meatDish.setMeatPrice();
//functions to add details to dish
std::cout << "You have added the following dish: " << std::endl;
std::cout << "Item number: \n" << meatDish.getMeatNumber() << std::endl;
std::cout << "Item Category: \n " << meatDish.getMeatCategory() << std::endl;
std::cout << "Item Description: \n" << meatDish.getMeatDescription(i) << std::endl;
std::cout << "Item Price: \n £" << meatDish.getMeatPrice(i) << std::endl;
std::cout << "Would you like to add another item? Press 1 for yes or 2 for no: " << std::endl;
std::cin >> option;
count += 1;
if (count == 5) {
std::cout << "Error. Exceeded maximum items.";
break;
} //breaks out of loop if more than 5 items
if (option == 2) { break; } //breaks out of loop when user is finished adding items
}//while loop to contain menu
}//brace for scope of case 1
}
return 0;
}
As you are using c++ class Meat you can use [] to instantiate N items
for example 5 objects
Meat meats[5];
If you want to modify 2nd object then
meats[1].setMeatDescription(<pass argument>);
You need to change that method using this keyword
this->meatDescription = <pass argument>;
No need to create meatDescription[] as an array
use this code https://pastebin.com/bCkzbFZV you can use meats[i].getMeatDescription()
You could create a new class called DishesContainer. This class could have :
a private std::vector => it will hold every instance
a public function to create a new dish
a public function to change any type of value inside a dish meat.
For exemple to change the description
class DishContainer{
public:
void ChangeDescription(int indexMeat, std::string newDescription){
meats_[indexMeat].setMeatDescription(newDescription);
}
private:
std::vector<Meat> meats_;
}

Setting a string value to none when a class related to it is deleted

I need help with something which I believe is simple. I can assign a student to a project. But when I delete the project, the student is still keeping the project name. I'm thinking of just renaming it back to "None" but I have no idea on how to do that. Help?
Edit
map<int, Student> mstore and vector<int> storeid added.
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <map>
using namespace std;
class Human {
public:
virtual void print() const = 0;
};
class Student : public Human {
protected:
string studname;
int studId;
string project;
public:
Student();
Student (string studname, int studId) : studname("Unknown"), studId(0), project("None")
{
cout << "A student is created: Name = " << studname
<< ". Id = " << studId << endl;
}
virtual void print() const {
cout << "Name = " << studname << ". Id = " << studId << ". Project = " << project <<endl; }
void setSName (string sname) { studname = sname; }
void setSID (int sID) { studId = sID; }
void printStudentInfo() const;
void printStudentInfoline() const;
};
void Student::printStudentInfo() const
{
cout << "\nStudent name: " << studname << endl;
cout << "Student ID: " << studId << endl;
cout << "Project: " << project << endl;
}
void Student::printStudentInfoline() const
{
cout << studId << ", " << studname << ", " << project << endl;
}
class Project {
protected:
string projname;
public:
vector <Student> students;
vector <int> storeid;
Project (string projname) : projname(projname) { cout << "Project " << projname << " created" << endl;}
void setPName (string projname) { this->projname = projname; }
void add (int& sid)
{
//student.setProject (projname);
storeid.push_back(sid);
}
int returnid(int& a)
{
return storeid[a];
}
int returnsize()
{ return storeid.size(); }
void printproj() const {
cout << endl << projname << " list: \n";
cout << "Student(s) : " << endl;
for (int i = 0; i < storeid.size(); i++){
cout << storeid[i] << endl;
}
}
void printprojname() const {
cout << projname << endl;
}
};
int main() {
string StudentName;
string ProjectName;
int Studentid;
Student *s1;
Project *p1;
vector<Student> store;
vector<Project> projstore;
map<int, Student> mstore;
map<int, Student>::const_iterator itr;
for (int n=0; n<3; n++) //loop to create 3 students
{
cout <<"Enter name : ";
getline(cin, StudentName);
cout <<"Enter ID : ";
cin >> Studentid;
s1 = new Student(StudentName, Studentid);
s1->setSName(StudentName);
s1->setSID(Studentid);
store.push_back(*s1);
mstore.insert(make_pair(Studentid, *s1));
cin.get();
}
//print map
for(itr=mstore.begin(); itr!=mstore.end() ;++itr)
itr->second.printStudentInfo();
//itr=mstore.begin()+2;
//itr.print();
cout << "Enter project name: ";
getline(cin, ProjectName);
p1 = new Project(ProjectName);
p1->setPName(ProjectName);
//Assigning student to project
cout << endl;
cout << "How many students? :" ;
int y;
cin >> y;
for ( int i = 0; i < y; i++){
cout << "Who would you like to add to this project?" << endl;
int x = 1;
for(itr=mstore.begin(); itr!=mstore.end() ;++itr)
itr->second.printStudentInfoline();
int insID;
cout << "Enter ID number: ";
cin >> insID;
p1->add(insID);
/*
for ( it = store.begin(); it != store.end(); ++it ) {
// For each friend, print out their info
cout << x << ". ";
it->printStudentInfoline();
x++;
}
x = 1;
int insS;
cout << "Enter number: ";
cin >> insS;
p1->add(store[(insS-1)]); //stores selected student into the object
*/
cout << "\nAdding Student done\n" << endl;
}
projstore.push_back(*p1);
//Mstore finds for related ids and displays them accordingly
cout << "print project"<< endl;
vector<Project>::iterator pt;
for ( pt = projstore.begin(); pt != projstore.end(); ++pt ) {
pt->returnsize();
for (int i=0; i <pt->returnsize(); i++){
cout << pt->returnid(i) << endl;
itr=mstore.find(pt->returnid(i));
itr->second.printStudentInfo();
}
}
cout << endl;
cout << "Deleting project" << endl;
cout << "What would you like to remove?" << endl;
int x = 1;
//storeid will display ids. How do I link them to `store` map?
for ( pt = projstore.begin(); pt != projstore.end(); ++pt ) {
cout << x << ". ";
pt->printprojname();
x++;
}
//Now to delete the selected project
int delP;
cout << "Enter number: ";
cin >> delP;
cin.ignore();
system("pause");
projstore.erase(projstore.begin()+delP-1);
// Students
cout << "\n Current students" << endl;
for(itr=mstore.begin(); itr!=mstore.end() ;++itr)
itr->second.printStudentInfo();
}
Look at how you add a Student to a Project:
void add (Student& student)
{
student.setProject (projname);
students.push_back (student); // <-- AHA!
}
First you assign the Project name to the Student, then the Project stores a copy of the Student. After that, the Project has no link to the original Student, and can't inform him/her of its own demise when the time comes.
You'll have to rethink this design; there are three major options: 1) the Students can look up their respective Projects in the store, 2) the Project can look up its Students in the students vector, or 3) the Project owns the Students (in which case they should probably be GraduateStudents).
EDIT:
If that's the way you want to do it, use map<int, Student> store to store the Students, using ID number as an index. Then a Project can have a vector<int> (or set<int>) of student ID numbers. It can look Students up in the store with ease.
EDIT:
To print out the entire collection of students:
for(map<int, Student>::const_iterator itr=store.begin(); itr!=store.end() ;++itr)
itr->second.print();
EDIT:
If the Project has a vector<int> of student ID numbers, then what argument do you think Project::add(?) should take?
EDIT:
The Project can act on a Student by means of the student ID number and access to mstore:
// in Project:
mstore[id].whatever()
EDIT:
Sometimes asking the right question -- or in this case, phrasing the question correctly -- is half the battle. 'Now how do I change "None" to the inserted project name?' A better way to put it is 'How does the Project change one of its Student's project from "None" to projname?' Once you put it that way, the answer is almost obvious:
// in Project:
mstore[id].setSProject(projname);
Note that Student does not yet have setSProject(string), you'll have to add it. Also, note that this solution is not ideal since 1) anybody can change a Student's project, and 2) a Student's project need not actually be the name of a real Project. There is more than one way to deal with these problems.