string firstname, lastname;
string phonenumber, email;
cout << "What is the first of the person that you would like to add? : ";
cin >> firstname;
cout << "What is the last of the person that you would like to add? : ";
cin >> lastname;
cout << firstname << " " << lastname << endl;
cout << "What is the phone number of that person? : ";
cin >> phonenumber;
I need help taking this user input and plugging it into an array. I honestly do not know how to do that, if I could get some help on that it would be great!
Create a struct named Record as follows
struct Record
{
string firstName, lastName,phone; //etc
};
If you know how many records you want to enter then you have to create an array of Record as follows
Record PersonInfo[5];
Now each index of PersonInfo let say PersonInfo[2] is a complete Record and you can access there fields like
PersonInfo[2].phone = "5655567" //etc
Now if you want to create array of Record but don't know the size then your best bet for now is to use a vector like follows. A vector is an array of changable size. You need to include the following header
#include<vector>
After wards you can do the following
vector<Record> PersonInfo //thats how vectors are declared
The name between <> bractes tell of what type you want a vector of ,you can write int as well.
Following is how you add items to a vector
Record r1,r2; // just for example
PersonInfo.push_back(r1);
PersonInfo. push_back(r2);
you may add any number of items in it and you can access them just like array as follows
PersonInfo[0] .lastName // its actually r1.lastName and so on
This may seem difficult for now you may want to learn vectors and their operations before going for dynamic memory allocation which requires that you understand what pointers are. I don't know that you know about pointers and how to use them that is why I reffered you vectors
Related
I'm making a program that keeps track of different employees. Some of the employees have partners (wifes and husbands), so all of the Employee objects have a data member called "Partner* partner" (a pointer to a Partner object).
My problem comes when I want to write an Employee to a file. I can successfully write all of the Employee data (name, address, birth date etc.) to the file, but I don't know how to write the partner to file. I have a function in the Partner class called "writeToFile" which outputs all of the partner data, but I don't know how to "connect" it to the correct Employee object. I tried to just output the "partner"-object to the end of the file, but that just added a bunch of zeros.
Should I use two separate files (one for employees and one for partners), or should I just append the partner data to the employee data? Wouldn't that mess up the file structure when reading it back in, since only some of the employees have partners and some of the partner objects just point to NULL?
My classes inherits each other, so both the Partner and Employee class inherits the Adult class, which again inherits the Person class.
Can anyone give me a "pointer" to what is the best way of writing an object which has a pointer to another object inside it? Here's my temporary code btw, if it is of any interest:
#include <iostream>
#include <fstream>
#include <cstring>
#include <cctype>
#include <cstdlib>
using namespace std;
const int MAXTXT = 80;
class Person {
protected:
char* firstname;
char birthdate[6];
public:
Person() {
char fname[MAXTXT];
cout << "First name: "; cin.getline(fname, MAXTXT);
firstname = new char[strlen(fname + 1)];
strcpy(firstname, fname);
cout << "Birth date (DDMMYY): ";
cin >> birthdate; cin.ignore();
}
void display() {
cout << "\nFirst name: " << firstname;
cout << "\nBorn: " << birthdate;
}
void writeToFile(ofstream & ut) {
ut << firstname << "\n" << birthdate;
}
};
class Adult: public Person {
protected:
char* lastname;
public:
Adult() {
char lname[MAXTXT];
cout << "Last name: "; cin.getline(lname, MAXTXT);
lastname = new char[strlen(lname + 1)];
strcpy(lastname, lname);
}
void writeToFile(ofstream & out) {
out << "\n" << lastname << "\n";
}
void display() {
cout << "\nLast name: " << lastname;
}
};
class Partner: public Adult {
private:
int phone1;
int phone2;
public:
Partner() {
cout << "Phone (mobile): "; cin >> phone1;
cout << "\nPhone (job): "; cin >> phone2; cin.ignore();
}
void writeToFile(ofstream & out) {
Person::writeToFile(out);
Adult::writeToFile(out);
out << "\n" << phone1 << " " << phone2;
}
void display() {
Person::display();
Adult::display();
cout << "\nPhone (mobile): " << phone1;
cout << "\nPhone (job): " << phone2;
}
};
class Employee: public Adult {
private:
int nr;
char* address;
Partner* partner;
public:
Employee() {
}
Employee(int n) {
char adr[MAXTXT];
nr = n;
cout << "Address: "; cin.getline(adr, MAXTXT);
address = new char[strlen(adr + 1)];
strcpy(address, adr);
partner = NULL;
}
void changePartner() {
Partner::Partner();
}
void writeToFile(ofstream & out) {
Person::writeToFile(out);
Adult::writeToFile(out);
out << nr << "\n" << address << endl;
}
void display() {
Person::display();
Adult::display();
cout << "\nAddress: " << address;
if(partner) {
partner->display();
}
}
int returnEmpNr() {
return nr;
}
};
Employee* employees[100];
int lastUsed = 0;
int main() {
}
void writeToFile() {
ofstream outfile("EMPLOYEES.DAT");
ofstream outfile2("PARTNERS.DAT");
outfile << lastUsed << "\n";
for(int i = 1; i <= lastUsed; i++) {
employees[i]->writeToFile(outfile);
}
A pointer is meaningless except to a single run of a program and could very well be meaningless by the time the file is read if the pointer at value has gone out of scope. The odds of the same Partner being in the same spot in memory, assuming space has even been allocated for it, the next time around could be as bad as 1 in 18,446,744,073,709,551,616 and being wrong has often fatal results. And those fatal results mean you got lucky. You could smash perfectly valid memory that belongs to something else, and results in behaviour that is weird, undefined, and much harder to debug than an outright crash.
In C++ pointers are often a sucker bet. Use them as a last resort because they can really ramp up the amount of code you need to write.
I recommend two lists (but not necessarily two files. Both lists can easily exist in one file) one of Partners and one of Employees. The Partners don't seem to need to know about the Employees, so save yourself some trouble and write out and read in the partner list first.
When writing the Employee list, don't store the Partner pointer because it won't work. Instead store the index of the Partner in the Partner list. Then when you read the Employee list, you can read the Partner's position in the Partner table look up that Partner, and point to them. This is why it's much easier to write and read the Partners first; it is hard to look up data in a list that hasn't been read yet.
Or ditch the concept of Partner pointers entirely and always use the index to look the Partner up. This is much safer approach, so long as you always append new partners to the list and never insert into the list or do something silly like shuffle the list.
While we're messing with pointers, take a good solid read of "What is The Rule of Three?" because you are heading into a quagmire of memory management carnage.
As written every time you copy an Employee, you will get another Employee that is copied stupidly. It copies the pointers, not the content, so you now have 2 Employee objects pointing to the same names and Partners. When you free the memory allocated to the partner and names, which you don't and really, really should, the other copy is pointing at memory that your program no longer owns and becomes a ticking time bomb just waiting to crash your program.
Using a std::vector<Partner> (note it is a vector of Partner, not Partner *. This allows the vector to own and manage all of the memory for you and not just the memory needed by the list) and indexes clears up the problem with Partners, because the std::vector manages the memory for you, but the names are still waiting to kill the program. Replacing the char *s with std::string will solve that problem, also by moving the memory management burden from your code to std::string where it was written for you some time in the 1990s and has been under use in millions of programs ever since. Not many bugs left to trip over after 20 years.
If you have to use pointers and arrays of pointers, you need to make custom destructors, copy constructors, move constructors, assignment operators and move operators. That's a lot of extra work.
But those vectors and strings contain pointers and you have to handle writing them carefully. This topic, serialization, has been beaten to death elsewhere, so here's a link to a reputable site that can probably handle it better than I can.
I am new to C++ and I am having a hard time figuring out how 2D arrays work.
I am making a program that takes a .txt file filled with "driver's license records" and reads them in, and then lets the user search through the "database" for for last name, age, or whether the driver is registered to vote (y/n).
A sample .txt file would look like this:
4
Chris Jones 19 Y 374122
Pat Smith 23 N 863901
Kyle Howard 31 Y 673911
Samantha Pratter 27 Y 874309
My main method is simply
int main(int argc, char* argv[])
{
Executive exec(argv[1]);
exec.run();
return (0);
}
Here is the code for my Executive class:
#include <iostream>
#include <fstream>
#include "Executive.h"
#include "DriversLicenseRecord.h"
using namespace std;
Executive::Executive(char* filename){
int n;
ifstream inp(filename);
inp >> n;
num_records=n;
DriversLicenseRecord** record = new DriversLicenseRecord*[n];
for(int i=0; i<n; i++){
record[i] = new DriversLicenseRecord(inp);
}
}
//here is where I am pretty much guessing
void Executive::run(){
int x=0;
do{
cout << "1: Query last name" << endl << "2: Query age range" << endl << "3: Query registered voters" << endl << "4: Quit" << endl;
cin >> x;
if(x==1){
string name;
cout << "Enter last name: ";
cin >> name;
/**for(int i=0; i<num_records; i++){
if(name==record[i]){
cout << record[i];
}
}*/
}
else if(x==2){
int max;
int min;
cout << "Enter age range: " << endl << "min: ";
cin >> min;
cout << "max: ";
cin >> max;
}
else if(x==3){
}
}while(x!=4);
}
And here is my DriversLicenseRecord class:
#include "DriversLicenseRecord.h"
using namespace std;
DriversLicenseRecord::DriversLicenseRecord(ifstream& inp){
inp >> first_name;
inp >> last_name;
inp >> age;
inp >> vote;
inp >> license;
}
Firstly I want to know if I'm reading in the values correctly, it is my understanding that it skips reading in white space, so the DriversLicenseRecord should be getting the correct values.
Secondly I have no idea how to search through this, and return the whole row.
Below is an example of output with a given .txt file:
1. Query last name
2. Query age range
3. Query registered voters
4. Quit
3 // user input
Chris Jones 19 Y 374122
Kyle Howard 31 Y 673911
Samantha Pratter 27 Y 874309
Just a small push in the right direction would be very helpful, I've been struggling with this problem all week and haven't made much progress.
Thank you!
There are a couple errors in your code, but first I'd like to say that there is (1) no need for a 2D array here and (2) you don't create a 2D array in Executive::Executive(). For (1): all you need in this task is an one-dimensional array (or container) of DriversLicenseRecord objects. Then, you can query the fields of individual objects and compare their values to the query to search for specific records. For (2), what you have created is simply an one-dimensional array of pointers to DriversLicenseRecord objects.
Here is where the errors appear.
Firstly, the variable records is local to the constructor. Once the c'tor returns, records will be destroyed. You won't be able to access it outside the constructor. Also, the memory you allocated will be lost, creating a memory leak.
Secondly, while creating the array is correct, iteration is not. Here's how you can iterate over the array and query the fields:
for(int i=0; i < num_records; i++){
// note the -> : because we're using a pointer, not the object itself
if(name == m_records[i]->first_name){
cout << m_records[i]->first_name;
// or, if you define operator<<(istream&, const DriversLicenseRecord&):
cout << *(m_records[i]);
}
Finally, why you had to use a dynamic array. Thing is, you don't know the number of entries until you read the file, and you can't create a variable length array other than with new, except inside a function as a local variable, but then see #1: it's lost on function exit. However, you could create a dynamic array of records, not pointers to records. For that, you need to supply a default constructor to DriversLicenseRecord, and then simply fill in the fields on the fly from the file. (Not the syntax you used with DriversLicenseRecord::DriversLIcenseRecord(istream&), that's not the default c'tor.)
Next, this is how I would go about this problem, using STL containers and algorithms.
1. Switch to std::vector, which has the benefit of being safer and more convenient to use.
2. I honestly disliked the idea of creating the D.L.R. class with an istream parameter. What you can do, if you want to use streams, is to define istream& operator>>(istream&, DriverLicenseRecord&) and then use the beautiful STL syntax like so:
std::istream& operator>>(std::istream& str, DriversLicenseRecord& rec)
{
std::string str;
str >> rec.first_name >> rec.last_name >> rec.age >> temp >> rec.license;
rec.can_vote = (temp == "Y");
return str;
}
Then some STL beauty:
class Executive {
typedef std::istream_iterator<DriversLicenseRecord> in_driver_it;
std::vector<DriversLicenseRecord> records;
public:
Executive(const std::string& file)
{
std::ifstream inp(file);
int n; inp >> n;
std::copy(in_driver_it(inp), in_driver_it(), std::back_inserter(records));
}
};
Same fot the output.
Long story short: here is the complete sample code using the standard library, which is not the shortest but simple on the other hand. Running out of space!
You can avoid using the 2D array.
Approach 1
Use a vector<string> instead. Makes things much simpler to handle.
Read from the text file and store each line as a string in the vector.
Then when you are searching for a particular query string all you need to do is process each string in the vector.
So for reading from the input text file you would do something like this:
ifstream inpFile(myfile.txt);
string line;
vector<string> myInpFile;
while(getline(inpFile,line))
{
myInpFile.push_back(line);
}
I'll leave the implementation of the string search as an exercise for you. Take a look at how to process strings here
Approach 2
Alternatively you can just read off what you need straight off the file into a string and then search the string. You wouldn't need DriversLicenseRecord in memory at all. But that's not what your TA appears to be looking for.
I am working on an assignment where we have to create a "student" object with a "course" member array that is dynamic so the user can enter from one course to as many as they'd like in the array. I've been trying this every which way and just cannot get the array to resize and accept new elements. Here is my code as it stands now:
cout << "Enter student name > ";
cin >> name;
Student firstStudent(name);
cout << endl << "Enter \"done\" when you are complete";
cout << endl << "Enter a new course : ";
cin >> course;
while (course != "done") {
numCourses++;
firstStudent.addElement(numCourses, course);//makes the array bigger
cout << endl << "Enter a new course : ";
cin >> course;
}//end while
member variables and constructor:
class Student
{
private:
string name;//name of student
string *dynArray = new string[1];//array
public:
Student::Student(string name)
{
this->name = name;
this->numC = 1;//initialized to one to start with
}
resizing and adding an element to the array:
void Student::addElement(int numCourses, string &course) {//DYNAMIC ARRAY
if (numCourses > this->numC) {//checks if there are more courses than there is room in the array
this->numC = numCourses; //this changes the member variable amount
dynArray[numCourses] = course;//adds new course to array
string *temp = new string[numC];//create bigger temp array
temp = dynArray;//write original to temp
delete[]dynArray; //this tells it that it's an array
dynArray = temp;//make dynarray point to temp
}
else {
dynArray[numCourses] = course;//adds new course to array
}
}//end addElement
Even if I manage to get rid of compile errors, it will often come up with runtime errors. I'm sure it has to do with pointers/copying arrays but I'm just learning and haven't yet mastered these concepts.
Edit: dynArray[numCourses] = course; creates a char array. ie if course = "one", dynArray[0] = "o", dynArray[ 1] = "n", etc. Does anyone know how to keep this from happening?
screenshot
The first line that that doesn't look quite correct is this one:
dynArray[numCourses] = course;
Before it is checked that numCurses > numC, which means that dynArray[numCourses] accesses memory out of bounds (the bounds are 0 to numC - 1.
The other thing that strikes me as interesting is that the addElement method takes numCourses as an argument. I would expect that it should behave similar to std::vector<T>::push_back. Are you sure this argument is necessary?
The last thing I want to comment on is that the values from dynArray are not copied. Have a look at std::copy_n on how to do the copy.
I'm not sure if this would be considered cheating, but here's a break down of how std::vector is implemented. You could use that as a reference and just pick out the parts you need.
http://codefreakr.com/how-is-c-stl-implemented-internally/
I am trying to create a program which allows a user to add an object of class called Vehicle to an inventory that is stored in a vector. The vector has an initial size of zero. Each object is a vehicle that the user enters the attributes of.
What I cannot wrap my head around is how to let the user keep adding vehicles if each vehicle needs to be its own separate object. How do you let C++ determine what the name of new objects should be if the user decides to keep adding more vehicles (objects) to the inventory (vector called carList).
Could someone guide me in the right direction? I apologize if this is obvious, I am new to the language. Must I do something that involves dynamically allocating objects or something similar?
Here is my (incomplete) code:
void addVehicle(vector<Vehicle> carList)
{
char stop; // Needed for stopping the do-while loop
string VIN = "", // Needed to hold user input for the VIN
Make = "", // Needed to hold user input for the Make
Model = ""; // Needed to hold user input for the Model
int Year = 0; // Needed to hold user input for the Year
double Price = 0.0; // Needed to hold user input for the Price
cout << "You have chosen to add a vehicle to your inventory.\n\n";
do
{
cout << "There are currently " << carList.size() << " vehicles in your inventory.\n\n"
<< "\t\t\tVehicle #" << (carList.size() + 1) << ": \n"
<< "\t\t___________________________\n\n";
Vehicle /*new object needs to go here*/
carList.push_back(/*new object from the line above*/);
// Prompt user to input VIN
cout << "VIN: ";
cin >> VIN;
// Prompt user to input Make
cout << "Make: ";
cin.ignore();
getline(cin, Make);
// Prompt user to input Model
cout << "Model: ";
getline(cin, Model);
// Prompt user to input Year
cout << "Year: ";
cin >> Year;
// Prompt user to input Price
cout << "Price: $";
cin >> Price;
Call to the overloaded constructor to store user input in object
/*(newly created object)*/.Vehicle::Vehicle(VIN, Make, Model, Year, Price);
// Ask user if they would like to enter another vehicle
cout << "\nWould you like to enter another vehicle? (Y/N):";
cin.ignore();
stop = cin.get();
} while (stop != 'N');
}
Any help would be appreciated. Thanks!
How about you first create the object and then push a copy into the vector?
Call to the overloaded constructor to store user input in object
Vehicle temp(VIN, Make, Model, Year, Price);
carList.push_back(temp);
But there's no need for the variable, really:
Call to the overloaded constructor to store user input in object
carList.push_back(Vehicle(VIN, Make, Model, Year, Price));
And if you have C++11, you can even construct the object directly in place:
Call to the overloaded constructor to store user input in object
carList.emplace_back(VIN, Make, Model, Year, Price);
Look ma, no copies!
I am en process of writing a simple program that assigns given student names into groups of whatever interval requested. Currently, I am focusing on the function that reads the name of the students.
Here is the code:
class student
{
public:
string nameFirst;
string nameLast;
};
student typeName()
{
student foo;
cout << "Type in a student's first name: ";
cin >> foo.nameFirst;
cout << "Type in that student's last name: ";
cin >> foo.nameLast;
cout << "\n";
return foo;
}
Since I cannot use getline(), I am forced to create two strings, one for each section of the student's full name. How can I rewrite this code to allow for it to take the full name without creating two variables and without using getline()? Or, if such isn't possible, how can I use a method within the class to combine the two strings into one?
You can just use
cin >> foo.nameFirst >> foo.nameLast;
cin >> will parse stops at white spaces, so you can just input the full name in one line split by space like James Bond.
To combine two strings into one:
string fullName = foo.nameFirst + " " + foo.nameLast;