How to iterate over string variables of a class object in C++? - c++

So here I have a class definition of a Car and then I create a carObject with it. I want the user to input values for all the variables in the carObject. As you see here, I have managed to get user input, but my approach to this problem is inefficient in my opinion.
I notice that all of the user inputs, except for the first one are very similar. I would like to use a loop of some kind to iterate over the declaration statements, or blocks of statements, and change the variable every time. I would like to put an if statement to enter different input only for the first iteration of the loop. I know that in bash I could use a string variable to stand for the variable name, but I don't know if that's possible in C++.
Notice that the object name does not change, but only the variables that are associated with it. I also use the same word for the user input, which preferably should be changed every iteration. I also have a series of arrays which are named similarly. The purpose of these arrays is to tell the user what options are available for a particular variable.
Although I have previous programming experience, I am relatively new to C++. A block of code that would serve as a solution to my problem that involves a call to another function would suit my purposes. Here is my code below.
#include <iostream>
#include <string>
using namespace std;
class Car {
public:
string Name;
string Model;
string Color;
string Transmission;
string Category;
};
int main() {
Car CarObject;
string modelOptions [3] = { "Ferrari", "Porsche", "Nissan" };
string colorOptions [4] = { "Blue", "Red", "Green", "White" };
string transmisionOptions [2] = { "Automatic", "Manual" };
string categoryOptions [3] = { "A", "B", "C" };
cout << "Enter " << "name" << " for Car 1." << endl;
cin >> carObject.Name;
cout << endl;
cout << "Enter " << "model" << " for Car 1." << endl;
cout << "Options are:";
for (const string &text: modelOptions) {
cout << " " << text;
}
cout << "." << endl;
cin >> carObject.Model;
cout << endl;
cout << "Enter " << "color" << " for Car 1." << endl;
cout << "Options are:";
for (const string &text: colorOptions) {
cout << " " << text;
}
cout << "." << endl;
cin >> carObject.Color;
cout << endl;
cout << "Enter " << "transmission" << " for Car 1." << endl;
cout << "Options are:";
for (const string &text: transmissionOptions) {
cout << " " << text;
}
cout << "." << endl;
cin >> carObject.Transmission;
cout << endl;
cout << "Enter " << "category" << " for Car 1." << endl;
cout << "Options are:";
for (const string &text: categoryOptions) {
cout << " " << text;
}
cout << "." << endl;
cin >> carObject.Category;
cout << endl;
...
return 0;
}

void Car::InputParameter(string& param, const string &msg, const vector<string>& options)
{
cout << msg << endl;
for (const string &text: options) {
cout << " " << text;
}
cout << "." << endl;
cin >> param;
cout << endl;
}
I think you might want something like this. You just call it for each member.

This block of code:
cout << "Enter " << "category" << " for Car 1." << endl;
cout << "Options are:";
for (const string &text: categoryOptions) {
cout << " " << text;
}
cout << "." << endl;
cin >> carObject.Category;
cout << endl;
… can be replaced with a call to a function like this:
carObject.Category = userInput( "category", categoryOptions );
Clearly it returns a string (that is, a std::string).
The options argument should better be made a vector<string>.
Then just replace the other similar blocks with ditto calls to that function.
Is it a good idea to make that function a member function of Car?
No.
Consider, for example, how to then use Car in a GUI program (Graphical User Interface).

Related

New to structures, I'm confused about how to return values out of a void function and put it into another function

my C++ class just started learning about developing structures. I'm stuck on a homework problem where I'm asked to write a program that uses a structure named movie_data and two movie_data variables to display information about a movie. I'm able to develop the movie_data structure correctly along with the two variable to outsoruce to a function named get_movie_info. However, because I set it as a void function, I'm unable to return anything produced by the get_movie_function to send to my movie_display function. I tried rewriting my functions to be of the movie_data structure data type, but that seemed to make things worse. The first function produces all the information correctly, but the second function doesn't output anything. Thank you for your time.
#include <iostream>
#include <iomanip>
using namespace std;
struct movie_data
{
string title;
string director;
int year_released;
int running_time;
};
//Function Prototype
void get_movie_info(movie_data movie1, movie_data movie2);
void movie_display(movie_data movie1, movie_data movie2);
int main()
{
movie_data movie1;
movie_data movie2;
get_movie_info(movie1, movie2);
movie_display(movie1, movie2);
return 0;
}
void get_movie_info(movie_data movie1, movie_data movie2)
{
//Get movie_data's title
cout << "Enter the title for the first movie: ";
//cin.ignore();
getline(cin, movie1.title);
cout << movie1.title << endl;
//Get movie_data's director
cout << "Enter the director's name for " << movie1.title << ": ";
//cin.ignore();
getline(cin, movie1.director);
cout << movie1.director << endl;
//Get movie_data's release year
cout << "Enter the release year for " << movie1.title << ": ";
cin >> movie1.year_released;
cout << movie1.year_released << endl;
//Get movie_data's running time
cout << "Enter the runtime of " << movie1.title << " in minutes: ";
cin >> movie1.running_time;
cout << movie1.running_time << " minutes" << endl;
//Get movie_data's title
cout << "Enter the title for the second movie: ";
cin.ignore();
getline(cin, movie2.title);
cout << movie2.title << endl;
//Get movie_data's director
cout << "Enter the director's name for " << movie2.title << ": ";
//cin.ignore();
getline(cin, movie2.director);
cout << movie2.director << endl;
//Get movie_data's release year
cout << "Enter the release year for " << movie2.title << ": ";
cin >> movie2.year_released;
cout << movie2.year_released << endl;
//Get movie_data's running time
cout << "Enter the runtime of " << movie2.title << " in minutes: ";
cin >> movie2.running_time;
cout << movie2.running_time << " minutes" << endl;
}
void movie_display(movie_data movie1, movie_data movie2)
{
//Display movie1 information
cout << "\nBelow is the data of the first movie:\n";
cout << "Movie Title: " << movie1.title << endl;
cout << "Director's Name: " << movie1.director << endl;
cout << "Release Year: " << movie1.year_released << endl;
cout << "Movie Runtime in minutes: " << movie1.running_time << endl;
//Display the movie information
cout << "\nBelow is the data of the second movie:\n";
cout << "Movie Title: " << movie2.title << endl;
cout << "Director's Name: " << movie2.director << endl;
cout << "Release Year: " << movie2.year_released << endl;
cout << "Movie Runtime in minutes: " << movie2.running_time << endl;
}
While #Kai's answer of using refrences would work and correctly would answer your original question, I suggest doing something else.
First, use a function to read in only one move_data and make it return that:
movie_data get_movie_info();
A possible implementation (using your code) could be like this:
movie_data get_movie_info(){
movie_data movie;
cout << "Enter the title for the first movie: ";
getline(cin, movie.title);
cout << "Enter the director's name for " << movie.title << ": ";
getline(cin, movie.director);
cout << "Enter the release year for " << movie.title << ": ";
cin >> movie.year_released;
cout << "Enter the runtime of " << movie.title << " in minutes: ";
cin >> movie.running_time;
return movie;
}
Now you can call it twice to read your info and it will return the movie data as the correct structure.
movie_data movie1 = get_movie_data();
If you need to have structs that can be edited, references are a good choice. For returning multiple values, there are better choices: An array of a suitable size (std::array), a Pair for two, or a vector of Objects.
It's better to avoid having output parameters (as a rule of thumb, break it if you need to and know why) as they are hard to grasp from the signature and hard to keep track of.
Notice, that you do everything twice. The point of using functions, is to not do everything twice, so you should write one function to do one thing and just call it with different parameters. For example in get_movie_info. A better design would be to create a function that creates exactly one movie_data and returns it:
movie_data get_movie_info()
{
movie_data result = {}; // That's the variable were we store the data
//Get movie_data's title ...
//Get movie_data's director ...
//Get movie_data's release year ...
//Get movie_data's running time ...
return result; // return the created movie data
}
The same goes for movie_display. Don't create a function that does exactly the same thing for two parameters, but create a function that does it one time and call it twice:
void movie_display(movie_data movie)
{
cout << "Movie Title: " << movie.title << endl;
//And so on ...
}
Then you combine both in the main like this:
int main()
{
movie_data movie1 = get_movie_info();
movie_data movie2 = get_movie_info();
std::cout << "data of the first movie:\n";
movie_display(movie1);
std::cout << "data of the second movie:\n";
movie_display(movie2);
return 0;
}
Update your function signatures to take references instead of values.
https://www.learncpp.com/cpp-tutorial/72-passing-arguments-by-value/
void get_movie_info(movie_data& movie1, movie_data& movie2)
void movie_display(const movie_data& movie1, const movie_data& movie2)

How to pass struct as parameter to other function for input, then output back at the original function

This is part of my project codes.
About the struct customer that I did, from welcomeScreen function I call the getInfo function for user to input the details (as you can see) and then return back the value to welcomeScreen function for output.
I can compile the codes, but the problem is there is no output for all the details after I input it (just blank)? Sorry if this is a dumb question cause im still a student.
struct customer
{
string name;
string email;
int number;
};
void welcomeScreen(); //prototype
void getInfo(struct customer cust); //prototype
void welcomeScreen()
{
struct customer cust; // struct declaration
const int SIZE=5;
system("CLS");
cout << setfill ('-') << setw (55) << "-" << endl;
cout << "\tWelcome to Computer Hardware Shop" << endl;
cout << setfill ('-') << setw (55) << "-" << endl;
cout << endl << "Type of hardwares that we sell:" << endl;
string item[SIZE]={"Monitor","CPU","RAM","Solid-State Drive","Graphic Card"};
for(int i=0;i<SIZE;i++)
cout << "\t" << i+1 << ". " << item[i] << endl;
getInfo(cust);
cout << endl;
cout << fixed << showpoint << setprecision (2);
cout << "Name: "<< cust.name << endl; // struct output
cout << "Email: "<< cust.email << endl;
cout << "Phone Number: " << cust.number << endl;
cout << endl;
}
void getInfo(struct customer cust)
{
cout << endl << "Enter name: ";
cin >> cust.name;
cout << "Enter email: ";
cin >> cust.email;
cout << "Enter phone number: ";
cin >> cust.number;
}
You probably want to pass a pointer or a reference, in this case recommend a reference because it means fewer changes to your code:
void getInfo(struct customer &cust); //prototype
Remember to change your function parameter as well.

How to use struct members in a struct's member function?

So the purpose of the program is to Create an array of 3 people, allow the user to populate the data in a for loop, ensure that the results are capitalized, and output the results.
These new projects instructions were to
1. Rewrite capitalize() as a method within the structure.
2. Rewrite printPerson() as a method within the structure
The program itself works just fine, it's just not in the format that my professor wanted. He said the point of it is to not use any arguments but again, I don't know what he means. I just started programming a few months ago and even though I'm trying I don't have a strong knowledge of the terminology.
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
struct Person {
string firstName;
string middleName;
string lastName;
int age;
string gender;
void capitalize(Person &arg);
void printPerson(Person arg);
};
Pretty sure these are the methods right here, but I'm not sure if the (person &arg) and (person arg) are the arguments itself or if they are parameters. I thought it was the "arg" part but I can't find a way to get the program to run without them as I'm pretty sure I need the & of operator to modify the information.
int main(void) {
Person myPerson;
Person a[3];
const int size = 5;
for (int i = 0; i <= 2; i++) {
cout << "What is First Name #" << i + 1 << "? ";
getline(cin, a[i].firstName);
cout << "What is Middle Name #" << i + 1 << "? ";
getline(cin, a[i].middleName);
cout << "What is Last Name #" << i + 1 << "? ";
getline(cin, a[i].lastName);
cout << "Age #" << i + 1 << "? ";
cin >> a[i].age;
cin.ignore();
cout << "Male or Female #" << i + 1 << "? ";
getline(cin, a[i].gender);
cout << endl;
}
for (int i = 0; i <= 2; i++) {
myPerson.capitalize(a[i]);
cout << "PERSON #" << i + 1 << endl;
cout << "~~~~~~~~~~~~~~~" << endl;
myPerson.printPerson(a[i]);
}
system("pause");
return 0;
}
Along with that, I don't know how to manipulate the functions to work without the "parameters/arguments" (I'm not sure the difference at this point) or without the "arg"
void Person::capitalize(Person &arg) {
transform(arg.firstName.begin(), arg.firstName.end(), arg.firstName.begin(), ::toupper);
transform(arg.middleName.begin(), arg.middleName.end(), arg.middleName.begin(), ::toupper);
transform(arg.lastName.begin(), arg.lastName.end(), arg.lastName.begin(), ::toupper);
}
void Person::printPerson(Person arg) {
cout << "\nFirst Name: " << arg.firstName << endl;
cout << "\nMiddle Name: " << arg.middleName << endl;
cout << "\nLast Name: " << arg.lastName << endl;
cout << "\nAge: " << arg.age << endl;
cout << "\nGender: " << arg.gender << endl;
cout << "\n\n";
}
The capitalize and the printPerson are now members (usually called methods) of the struct Person. This means that they operate on the member variables of an Person instance. Like this, you can just access all the classes members in these methods. See the following code. I also completed it with a constructor and made it slightly more readable.
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
struct Person {
public:
Person();
void readFromUserInput();
void capitalize();
void print();
public:
string firstName;
string middleName;
string lastName;
int age;
string gender;
};
Person::Person() :
firstName(""),
middleName(""),
lastName(""),
age(0),
gender("")
{
}
void Person::readFromUserInput()
{
cout << "What is the First Name ? ";
getline(cin, firstName);
cout << "What is Middle Name ? ";
getline(cin, middleName);
cout << "What is Last Name ? ";
getline(cin, lastName);
cout << "Age ? ";
cin >> age;
cin.ignore();
cout << "Male or Female ? ";
getline(cin, gender);
}
void Person::capitalize()
{
transform(firstName.begin(), firstName.end(), firstName.begin(), ::toupper);
transform(middleName.begin(), middleName.end(), middleName.begin(), ::toupper);
transform(lastName.begin(), lastName.end(), lastName.begin(), ::toupper);
}
void Person::print()
{
cout << "\nFirst Name: " << firstName << endl;
cout << "\nMiddle Name: " << middleName << endl;
cout << "\nLast Name: " << lastName << endl;
cout << "\nAge: " << age << endl;
cout << "\nGender: " << gender << endl;
cout << "\n\n";
}
int main(void)
{
const int NUM_PERSONS = 3;
Person a[NUM_PERSONS];
for (int i = 0; i < NUM_PERSONS; i++)
{
cout << "### " << (i + 1) << ". User:" << endl;
a[i].readFromUserInput();
cout << endl;
}
for (int i = 0; i < NUM_PERSONS; i++)
{
a[i].capitalize();
cout << "PERSON #" << i + 1 << endl;
cout << "~~~~~~~~~~~~~~~" << endl;
a[i].print();
}
system("pause");
return 0;
}

How to get variable values from main and send them to a function?

I have encountered a problem while running this code in my IDE. You can see very early on that I've attempted to use a function. The reason for this is to save memory later on by outputting text, but the problem occurs with the variables in the function. The classType variable is uninitialized, how do I prevent this? I have defined them in main, but when I try to output the text with the variables from main then it doesn't work properly.
#include<iostream>
using namespace std;
string getName()
{
   string charName;
   int classType;
   cout << "What is your " << classType << "'s name?" << endl;
   cin >> charName;
   return charName;
}
int main()
{
   int classType; //Later we will ask the user what class they're playing.  
   string charName;
   /*We will use a function to ask a question.  
   We use a function to save memory instead of copy-pasting the text*/
   cout <<"Welcome to \"Orcs and Ogres\"" << endl;
   cout << "What class do you want to play?  " << endl;
   cout << "\tType 1 for Warrior class]" << endl;
   cout << "\tType 2 for Archer class ]" << endl;
   cout << "\tType 3 for Mage class   ]" << endl;
   cin >> classType;
   if(classType == 1)
   {
       cout << endl << "You are a warrior" << endl;
       string classType;
       classType = "warrior";
       getName();
   }
   else if(classType == 2)
   {
       cout << endl << "You are an archer" << endl;
       string classType;
       classType = "archer";
       getName();
   }
   else if(classType == 3)
   {
       cout << endl << "You are a mage" << endl;
       string classType;
       classType = "mage";
       getName();
   }
   else
   {
       cout << endl << "UserError:  Number too high or too low";
   }
}
On the lines of code that use getName(), it outputs something like "What is your blank's name?" instead of the proper classType. I want to know how I can send variable values to a function from main so that it outputs text properly here.
The reason why it's not working is because your getName function has no knowledge of whats stored in the classType variable. Read on how function variable scope works to understand the whole mechanism works might be beneficial.
If you wish to keep the current implementation of your program. Re-write your getName function to accept the string class as a parameter
string getName(string classType)
{
string charName;
cout << "What is your " << classType << "'s name?" << endl;
cin >> charName;
return charName;
}
and in your main you'd call the function as follow :
getName("Warrior"); // to ask warrior for a warriors' name
getName("Mage"); // to ask for a mage's name.
You may also want to add to include the string library at the top of your file as not having it might also cause your code to simply not work. As well as making sure to properly store the name returned from your getName() function as follow :
string name = getName("Warrior");
Also , as others have said , maybe reading a bit more on how function receive and return values might be beneficial to you.
It is as simple as this. Try this updated code...
#include<iostream>
using namespace std;
string getName(string classType)
{
string charName;
cout << "What is your " << classType << "'s name?" << endl;
cin >> charName;
cout<<"your "<<classType<< "'s name is "<<charName<<endl;
return charName;
}
int main()
{
int Type;
string charName;
cout <<"Welcome to \"Orcs and Ogres\"" << endl;
cout << "What class do you want to play? " << endl;
cout << "\tType 1 for Warrior class]" << endl;
cout << "\tType 2 for Archer class ]" << endl;
cout << "\tType 3 for Mage class ]" << endl;
cin >> Type;
if(Type == 1)
{
cout << endl << "You are a warrior" << endl;
string classType;
classType = "warrior";
getName("warrior");
}
else if(Type == 2)
{
cout << endl << "You are an archer" << endl;
string classType;
classType = "archer";
getName("archer");
}
else if(Type == 3)
{
cout << endl << "You are a mage" << endl;
string classType;
classType = "mage";
getName("mage");
}
else
{
cout << endl << "UserError: Number too high or too low";
}
return 0;
}

I am trying to use a do while loop to repeat a certain portion of my program and it refuses to execute properly

Okay so as the title said its refusing to execute the stuff right under the "do" function even though as far as i can tell all the parameters for a repeat have been fulfilled. So far what i get when i run the program is something along the lines of...
"Would you like to search another name?
Please enter Y for yes and n for no:"
looping over and over when i press y
#include <iostream>
#include <string>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <cstdlib>
using namespace std;
int main()
{
vector <string> vName, vID, vClass;
string sName, sID, sClass, sSearch, cQuestion;
int iSize, iStudent;
// Display initial vector size
iSize = vName.size();
cout << "Student list starts with the size:" << iSize << endl;
// Get size of list from user
cout << "How many students would you like to add?" << endl;
cin >> iStudent;
cin.ignore();
// Get names, ids, and classes
for (int i = 0; i < iStudent; i++)
{
cout << "Student" << i + 1 << ":\n";
cout << "Please enter the student name: ";
getline(cin, sName);
vName.push_back(sName);
cout << "Enter ID number ";
getline(cin, sID);
vID.push_back(sID);
cout << "Enter class name ";
getline(cin, sClass);
vClass.push_back(sClass);
}
// Display header
cout << "The list of students has the size of: " << iStudent << endl;
cout << "The Student List" << endl;
cout << "\n";
cout << "Name:" << setw(30) << "ID:" << setw(38) << "Enrolled Class : " << endl;
cout << "--------------------------------------------------------------------------";
cout << "\n";
// for loop for displying list
for (int x = 0; x < vName.size() && vID.size() && vClass.size(); x++)
{
cout << vName[x] << "\t \t \t" << vID[x] << "\t \t \t" << vClass[x] << endl;
}
// Sorting function
cout << "\n";
cout << "The Student List after Sorting:" << endl;
cout << "\n";
sort(vName.begin(), vName.end());
for (int y = 0; y < vName.size(); y++)
{
cout << vName[y] << endl;
}
cout << "\n";
// Search function
do
{
cout << "Please Enter a name to be searched:" << endl;
getline(cin, sSearch);
if (binary_search(vName.begin(), vName.end(), sSearch))
{
cout << sSearch << " was found." << endl << endl;
}
else
{
cout << sSearch << " was not found." << endl << endl;
}
cout << "Would you like to search another name?" << endl << endl;
cout << "Please enter Y for Yes and N for No:" << endl << endl;
cin >> cQuestion;
} while (cQuestion == "Y" || cQuestion == "y");
cout << "Thank you for using this program!" << endl;
return 0;
}
Edit:
Posted whole program, please excuse any grammatical mistakes, I'm just trying to get the program down before i go in there and make it pretty.
The tail of your loop does this:
cout << "Please enter Y for Yes and N for No:" << endl << endl;
cin >> cQuestion;
which will consume your string if you entered one, but leave the trailing newline in the input stream. Thus when you return to the top of the loop after entering Y or y, and do this:
cout << "Please Enter a name to be searched:" << endl;
getline(cin, sSearch);
the getline will extract an empty line.
How to consume the unread newline from the input stream is up to you. You will likely just end up using .ignore() as you did prior in your program. Or use getline to consume cQuestion. You have options. Pick one that works.
And as a side note, I would strongly advise you check your stream operations for success before assuming they "just worked". That is a hard, but necessary, habit to break. Something like this:
do
{
cout << "Please Enter a name to be searched:" << endl;
if (!getline(cin, sSearch))
break;
if (binary_search(vName.begin(), vName.end(), sSearch))
{
cout << sSearch << " was found." << endl << endl;
}
else
{
cout << sSearch << " was not found." << endl << endl;
}
cout << "Would you like to search another name?" << endl << endl;
cout << "Please enter Y for Yes and N for No:" << endl << endl;
} while (getline(cin,cQuestion) && (cQuestion == "Y" || cQuestion == "y"));
If cQuestion is a char array then you need to use strcmp or stricmp to compare it with another string i.e. "Y" and "y" in this case. If cQuestion is a single char then you need to compare with 'Y' and 'y' (i.e. with a single quote)
Strings in C++ are not first class types therefore they do not have some of the string operation that exist for other basic types like ints and floats. You do have std::string as part of the standard C++ library which almost fulfills the void.
If you just change the type of cQuestion to std::string your code should work but if you want to stick with chars then you will need to change the quote style.