I have two dynamically allocated array of class objects - student and staff. When a user inputs the age, based on the age I would like to either update the elements of student array or staff array.
But my code below doesn't work. The variable person doesn't get reassigned to staff once assigned to student. All the data I enter goes into student only no matter the age I enter. What is wrong with my code? How can I have one variable and assign it either one or the other array elements based on a condition check?
#include <iostream>
using namespace std;
int main()
{
class info
{
public:
int unique_id;
char* hair_color;
int height;
int weight;
};
class info* student;
student = new info[10];
class info* staff;
staff = new info[10];
for (int i=0; i<10;i++)
{
class info& person = student[i];
int age ;
cout<< "enter age"<<endl;
cin >> age;
if( age > 18 )
{
person = staff[i]; // This assignment doesn't work ??
}
cout<< "enter unique_id"<<endl;
cin >> person.unique_id;
cout<< "enter height"<<endl;
cin >> person.height;
cout<< "enter weight"<<endl;
cin >> person.weight;
}
cout<<" Student "<<student[0].unique_id<<" "<<student[0].height<<"\" "<<student[0].weight<<endl;
cout<<" Staff "<<staff[0].unique_id<<" "<<staff[0].height<<"\" "<<staff[0].weight<<endl;
return 0;
}
You cannot reseat a reference. Once it's set, it's stuck there and any attempts to reassign the reference will be interpreted as a request to assign to the referenced variable. This means
person = staff[i];
is actually copying staff[i]; into person which is an alias (another name) for student[i]. student[i] will continue to receive the inputs read from the user.
The easiest way around this given your current code is to replace the reference with a pointer, which can be reseated.
class info* person = &student[i]; // using pointer
int age ;
cout<< "enter age"<<endl;
cin >> age;
if( age > 18 )
{
person = &staff[i]; // using pointer, but note: nasty bug still here
// You may have empty slots in staff
}
cout<< "enter unique_id"<<endl;
cin >> person->unique_id; // note the change from . to ->
....
But There are ways around this. You can delay creating the reference until you know which array to use. This requires shuffling around a lot of your code and would still leave you with unused elements in the array if you are not careful.
Fortunately there is a much better way to do this using std::vector from the C++ Standard Library's container library.
std::vector<info> student;
std::vector<info> staff;
for (int i=0; i<10;i++)
{
info person; // not a pointer. Not a reference. Just a silly old Automatic
int age ;
cout<< "enter age"<<endl;
cin >> age;
// gather all of the information in our Automatic variable
cout<< "enter unique_id"<<endl;
cin >> person.unique_id;
cout<< "enter height"<<endl;
cin >> person.height;
cout<< "enter weight"<<endl;
cin >> person.weight;
// place the person in the correct vector
if( age > 18 )
{
staff.push_back(person);
}
else
{
student.push_back(person);
}
}
Related
I am new to programming, and am trying to figure out one thing at a time.
What is the correct format for inputting information into the vector in line 13?
I am getting an error of StudentInformation has no member studentNames.
1 struct StudentInformation
2 {
3 std::string studentNames{};
4 int studentScores{};
5 };
6
7 void getInformation( int numberOfStudents, std::vector < StudentInformation> student )
8 {
9 for (int enterNameItterate{ 0 }; enterNameItterate = numberOfStudents; ++enterNameItterate)
10 {
11 std::cout << "Enter the name of the next student: ";
12 std::string studentName;
13 std::cin >> student.studentNames[enterNameItterate]{ studentName };
14 std::cout << "Enter the score of student: " << student.studentNames[enterNameItterate]{ studentName } << ": ";
15 int studentScore;
16 std::cin >> student.studentScores[enterNameItterate]{ studentScore };
17 }
18 }
You just want
std::cin >> student[enterNameItterate].studentNames;
If you dumb it down to just
std::string s;
std::cin >> s;
It might make it more obvious. The above code assumes you've already allocated the space for your vector, otherwise you would want this instead:
std::string studentName;
std::cin >> studentName;
int score = 0;
std::cin >> score;
student.emplace_back({studentName, score});
Something else that will quickly bite you on the bum: you're passing your vector into getInformation as a copy which means when you alter it within the function, you're not altering the actual object, but a copy of it. You can solve this by returning the vector of inputted information, or taking the vector by reference. Either:
std::vector<StudentInformation> getInformation(int numberOfStudents);
OR
void getInformation(int numberOfStudents, std::vector<StudentInformation>& student); // notice the &
I would change your structure slightly to provide a handy constructor function that takes a name and a score, e.g.
struct StudentInformation
{
StudentInformation() = default;
StudentInformation(const std::string& name, int score)
: name(name), score(score) {}
// renamed vars to something nicer.
std::string name{};
int score{};
};
I would change your function arguments slightly, so that you take a reference to an array of students. (Notice the '&' in the argument?)
void getInformation( int numberOfStudents, std::vector<StudentInformation>& students )
{
// simplifying the naming here. 'i' is generally known to be a counter.
for (int i = 0; i = numberOfStudents; ++i)
{
// some temp vars to store entered fields
std::string studentName;
int studentScore;
// get the data from the user
std::cout << "Enter the name of the next student: ";
std::cin >> studentName;
std::cout << "Enter the score of student: " << studentName << ": ";
std::cin >> studentScore;
// construct a new object at the end of the vector.
// this will call the constructor that takes two args
students.emplace_back(studentName, studentScore);
}
}
I've made an addDepartment function that takes a structure as an argument. When I enter input to initialize the "dept[counter].departmentHead" at the bottom of the function, it triggers the error message.
I'm copying the logic from another code I wrote using classes instead of structures and that one works fine so I'm really not sure why this one isn't working. Tried messing with the index to make sure I wasn't going over the size of the array but that doesn't seem to fix the issue.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstring>
using namespace std;
struct Department{
string departmentName;
string departmentHead;
int departmentID;
double departmentSalary;
};
//...
Department addDepartment(Department dept[3]){
int repeat=0;
int counter=0;
if (counter>2){
cout<<"The array is full, you can not add any more Departments."<<endl;
}
else{
cout << "Please Enter Department Details:"<<endl;
cout << "Department ID : ";
cin >> dept[counter].departmentID;
for(int x=0; x<3; x++){
for (int y=x+1; y<3; y++){
if(dept[x].departmentID==dept[y].departmentID)
repeat++;
}
}
if(repeat!=0)
cout<<"Value must be unique!"<<endl;
else{
cout << "Department Name : ";
cin >> dept[counter].departmentName;
cout << "Head of Department : ";
cin >> dept[counter].departmentHead;
counter++;
}
}
}
//...
int main()
{
Employee emp[5];
Department dept[3];
initialID(emp,dept,0);
initialID(emp,dept,1);
int response;
while(response!=6){
displayMenu();
cout<< "Please make a selection : \n";
cin >> response;
while((response!=1)&&(response!=2)&&(response!=3)&&(response!=4)&&(response!=5)&&(response!=6)){
cout<< "Please enter a valid choice (1 - 6): ";
cin >> response;
}
if(response==1){
addDepartment(dept);
}
else if(response==2){
//addEmployee(emp,dept);
}
else if(response==3){
}
else if(response==4){
}
else if(response==5){
//salaryReport(dept);
}
}
cout << "Thank you, goodbye.";
}
Why it breaks.
The addDepartment function never actually returns a department. When the function exits, the space where the return newly created Department would be is left uninitialized. This causes undefined behavior. The compiler tries to destruct the Department object like it normally would, but because it was never initialized, free gets called on garbage (causing the error).
We can fix this by adding a line to addDepartment returning the actual department:
Department addDepartment(Department dept[3]){
int repeat=0;
int counter=0;
if (counter>2){
cout<<"The array is full, you can not add any more Departments."<<endl;
}
else{
cout << "Please Enter Department Details:"<<endl;
cout << "Department ID : ";
cin >> dept[counter].departmentID;
for(int x=0; x<3; x++){
for (int y=x+1; y<3; y++){
if(dept[x].departmentID==dept[y].departmentID)
repeat++;
}
}
if(repeat!=0)
cout<<"Value must be unique!"<<endl;
else{
cout << "Department Name : ";
cin >> dept[counter].departmentName;
cout << "Head of Department : ";
cin >> dept[counter].departmentHead;
counter++;
}
}
return /* some department */;
}
Alternatively, you could make addDepartment void.
Other considerations. Don't pass raw C arrays to functions. It doesn't do what you intend.
If you want to pass a copy of an array, pass a std::array, which will be copied automatically:
Department addDepartment(std::array<Department, 3> dept);
If want to access the elements of an existing array, pass a pointer:
Department addDepartment(Department* dept, int count);
One problem that I see is that you are creating an array of 3 Department objects in main and assuming that you have 5 elements in initialID.
Change main to create an array of 5 Department objects.
int main()
{
Employee emp[5];
Department dept[5];
...
In my code, I want to add one student info into my class pointer array and the array size will increase each time a new student is added. Here is my code:
My header file:
class Student{
public:
int studentID;
char studentName[20];
int currentEnrollment;
Student();
void AddStudent(Student *tempStudent[], int countStudent, int sizeOfArray);}
My Class definition file:
void Student::AddStudent(Student *tempStudent[], int countStudent, int sizeOfArray)
{
for (int i = countStudent; i < sizeOfArray; i++)
{
cout << "Please enter student id (4 digits only): ";
cin >> tempStudent[i]->studentID;
cout << "Please enter student name: ";
cin >> tempStudent[i]->studentName;
}
}
My Main.cpp file
int *totalStudent = new int;
*totalStudent = 1;
int i, j, countStudent = 0;
int sizeOfArray = *totalStudent;
Student *newStudent[*totalStudent];
//Each time a new student is added, I will allocate a new memory for the array element, then add student Info using function.
for (i = countStudent; i < *totalStudent; i++)
{
newStudent[i] = new Student;
newStudent[i]->AddStudent(newStudent, countStudent, sizeOfArray);
countStudent++;
*totalStudent++;
}
When I run my code, I get an undefined reference error, so I do not know If I am able to increase my array or not. I intend to use C++ syntax so I use new and delete. Thank you for your help.
P.S: Here is my new code and it runs great, the only missing is the studentID for the first element in array.
In my main class:
int numStudent = 0;
int i, j, countStudent = 1;
Student *newStudent = new Student[countStudent];
AddStudent(newStudent, countStudent, numStudent);
My Student.h
class Student{
public:
int studentID;
char studentName[20];
int currentEnrollment;
};
Student AddStudent(Student *newStudent, int &countStudent, int &numStudent);
and My Student.cpp
Student AddStudent(Student *newStudent, int &countStudent, int &numStudent)
{
Student tempStudent;
cout << "Please enter student id (4 digits only): ";
cin >> tempStudent.studentID;
cout << "Please enter student name: ";
cin >> tempStudent.studentName;
newStudent[numStudent] = tempStudent;
numStudent++;
if (numStudent == countStudent)
{
Student *newStudentSize = new Student[countStudent + 1];
for (int i = 0; i < numStudent; i++)
{
newStudentSize[i] = newStudent[i];
}
delete []newStudent;
return *newStudentSize;
countStudent += 1;
}
}
Running this code will give me the following result:
StudentID: 11
StudentName: Dat
StudentID: 23
StudentName: Michael
Printing:
StudentID: 0
StudentName: Dat
StudentID: 23
StudentName: Michael
While it doesn't make sense to increase the array for each new student (it's inefficient) here's one way you can do it (I didn't even try to make your code compile because it has a number of issues and is unnecessarily complicated). Note that tempStudent (in the code snippet below) doesn't even have to be created using new. This solution stores Student objects in the students array (although it's easy to modify it to store Student object pointers instead). That said, usually, you'll just want to create an array of large enough size to accomodate all students (just set studentCount to some appropriate number and not 1 like in the example below).
class Student{
public:
int studentID;
char studentName[20];
int currentEnrollment;
Student(){};
};
int main(){
int studentCount=1;
Student * students = new Student[studentCount];
int numStudents=0;
bool done=false;
char finished='N';
while (!done){
//Student *tempStudent = new Student();
//create a Student on the stack
Student tempStudent;
cout << "Please enter student id (4 digits only): ";
//No input checking is done here
cin >> tempStudent.studentID;
No input checking is done here
cout << "Please enter student name: ";
cin >> tempStudent.studentName;
students[numStudents] = tempStudent;
numStudents++;
cout << "Stop entering students: Y or N";
cin >> finished;
done = finished=='Y' or finished=='y' ? true : false;
if(numStudents==studentCount){
students = ReallocateStudents(students, studentCount, studentCount*2);
studentCount *= 2;
}
}//end while
//print the students info
for(int i=0;i<numStudents;i++){
Student st = students[i];
cout << st.studentID << " " << st.studentName << std::endl;
}
//deallocate the students array or if you place this in the main like you did, the program will exit immediately so there's no need to deallocate
return 0;
}
Student * ReallocateStudents(Student* st, int oldSize, int newSize){
Student * newStudents = new Student[newSize];
//copy the existing values from the old array to the new one
for(int i=0;i<oldSize;i++){
newStudents[i] = st[i];
}
delete [] st; //delete the old array
return newStudents;
}
UPDATE:
Since you don't want to do everthing in the main(), just create a free AddStudents function and do everything there. Alternatively, you can create a
static function inside the Student class. It makes no sense to create AddStudent as a member of Student because that would require you to use an instance of Student to add a new instance, which makes for poor design (not to mention technical issues etc).
int main(){
// some code here
Students * allStudents = AddStudents();
//print students
}//end main
Students * AddStudents(){
int studentCount=1;
Student * students = new Student[studentCount];
int numStudents=0;
bool done=false;
char finished='N';
while (!done){
//create a Student on the stack
Student tempStudent;
cout << "Please enter student id (4 digits only): ";
//No input checking is done here
cin >> tempStudent.studentID;
No input checking is done here
cout << "Please enter student name: ";
cin >> tempStudent.studentName;
students[numStudents] = tempStudent;
numStudents++;
cout << "Stop entering students: Y or N";
cin >> finished;
done = finished=='Y' or finished=='y' ? true : false;
if(numStudents==studentCount){
students = ReallocateStudents(students, studentCount,
studentCount*2);
studentCount *= 2;
}
}//end while
return students;
}
This is simple and easy to both understand and maintain so I suggest using this approach.
addStudent does not do anything with the Student object it belongs to. So there is no need to put it in the 'Student' class. (Or you could rather rewrite it so it does something with the student object it belongs to). And it currently does not "add" anything, so the name is confusing.
What is technically wrong with it depends on what you want it to do. Currently it initializes student objects expected to already exist and pointed to by an array, from a specific array index, to the end of the array. That could well be a useful function, if that is what you want it to do. But you then must call it correctly with an array of pointers that point to valid Student objects, which you currently do not.
Currently in main you have a loop that initializes pointers in an array. And each time you initialize a pointer, you call AddStudent(..). The problem is that 'AddStudent()' tries to initialize ALL the student pointed to by your array.
This has two major problems (In addition to all the other problems with your loop).
Each time you create a new student, all your existing students will be
initialized again with new input from std::cin. (So for n students, you will
try to do n*n initializations)
While the loop in main is running, not all pointers in your array points
to existing Student objects. This may result in important data being
overwritten, a program crash or something totally different and unexpected.
You should sit back and reevaluate how you want to do things. Trying to fix single bugs in your existing code, one after another, will just create more bugs.
Just a hint to get you started:
class Student
{
public:
int studentID;
char studentName[20];
int currentEnrollment;
Student();
void init_from_cin();
};
And in your class definition file:
void Student::init_from_cin()
{
cout << "Please enter student id (4 digits only): ";
cin >> studentID;
cout << "Please enter student name: ";
cin >> studentName;
}
If you create a new Student like this:
Student *new_student = new Student;
new_student->init_from_cin();
Then after calling init_from_cin(), the Student object pointed to by new_student should be initialized.
How to create and initialize multiple Student objects in a loop, is left as exercise for the reader. But when you do it, you should understand what your lower and upper bounds of your loop are supposed to be. And you should also understand why moving the upper bound further away while your loop is running is a bad idea.
And never forget that sane programming languages start array indexing with 0.
This is a class assignment that must be done using a dynamically created array of Course. I am trying to read into each member variable inside of course inside of my for loop but I'm not really sure how to do it. I did it with my student struct but the difference in this being an array is messing me up because I'm not sure how to proceed with it.
My problem is in the readCourseArray function when trying to read in struct members. If anyone could tell me how I do that I'd be appreciative. I know using the new operator isn't ideal along with many of the pointers being unnecessary but it is just how my instructor requires the assignment to be turned in.
#include <iostream>
#include <string>
using namespace std;
struct Student
{
string firstName, lastName, aNumber;
double GPA;
};
struct Course
{
int courseNumber, creditHours;
string courseName;
char grade;
};
Student* readStudent();
Course* readCourseArray(int);
int main()
{
int courses = 0;
Student *studentPTR = readStudent();
Course *coursePTR = readCourseArray(courses);
delete studentPTR;
delete coursePTR;
system ("pause");
return 0;
}
Student* readStudent()
{ Student* student = new Student;
cout<<"\nEnter students first name\n";
cin>>student->firstName;
cout<<"\nEnter students last name\n";
cin>>student->lastName;
cout<<"\nEnter students A-Number\n";
cin>>student->aNumber;
return student;
}
Course* readCourseArray(int courses)
{
cout<<"\nHow many courses is the student taking?\n";
cin>>courses;
const int *sizePTR = &courses;
Course *coursePTR = new Course[*sizePTR];
for(int count = 0; count < *sizePTR; count++) //Enter course information
{
cout<<"\nEnter student "<<count<<"'s course name\n";
cin>>coursePTR[count]->courseName>>endl;
cout<<"\nEnter student "<<count<<"'s course number\n";
cin>>coursePTR[count]->courseNumber;
cout<<"\nEnter student "<<count<<"'s credit hours\n";
cin>>coursePTR[count]->creditHours;
cout<<"\nEnter student "<<count<<"'s grade\n";
cin>>coursePTR[count]->grade>>endl;
}
return coursePTR;
}
Array subscript operator return an element of the array.
coursePTR[count] is equivalent to incrementing the pointer to the start of array and dereferencing the result, like: *(coursePTR + count). What you get is an object (or a reference to one) of type Course. So you'll need to use 'dot' operator, not 'arrow' operator to access the elements:
cin >> coursePTR[count].creditHours;
You've got another error:
cin >> coursePTR[count].courseName >> endl;
^^^^
This won't compile. endl can only be used on output streams.
Course* readCourseArray(int &courses); // Update the definition to pass "courses" by reference.
Course* readCourseArray(int &courses) // Pass the courses by reference so that your main() has the value updated.
{
cout<<"\nHow many courses is the student taking?\n";
cin>>courses;
/*
You don't need this line.
*/
// const int *sizePTR = &courses;
/*
You've allocated space for "courses" no. of "Course" objects.
Since this is essentially an array of "Course" object, you
just have to use the "." notation to access them.
*/
Course *coursePTR = new Course[courses];
/*
"endl" cannot be used for input stream.
*/
for(int count = 0; count < courses; count++) //Enter course information
{
cout<<"\nEnter student "<<count<<"'s course name\n";
cin>>coursePTR[count].courseName;
cout<<"\nEnter student "<<count<<"'s course number\n";
cin>>coursePTR[count].courseNumber;
cout<<"\nEnter student "<<count<<"'s credit hours\n";
cin>>coursePTR[count].creditHours;
cout<<"\nEnter student "<<count<<"'s grade\n";
cin>>coursePTR[count].grade;
}
return coursePTR;
}
I have to learn memory management in class and how to dynamically allocate memory with the new operator.
I have a struct that is
struct Course
{
int courseNumber, creditHours;
string courseName;
char grade;
};
I am trying to fill the member variables with a for loop but I am unsure how to use a getline with courseName. I was able to use a regular cin but it won't work if the class name has spaces.
Below is my code and what I've tried but I get a arguement error that courseArray is undefined.
Course* readCourseArray(int &courses) //Read Courses
{
cout<<"\nHow many courses is the student taking?\n";
cin>>courses;
const int *sizePTR = &courses;
Course *coursePTR = new Course[*sizePTR];
for(int count = 0; count < *sizePTR; count++) //Enter course information
{
cout<<"\nEnter student "<<count+1<<"'s course name\n";
getline(cin,courseArray[count].courseName);
cout<<"\nEnter student "<<count+1<<"'s course number\n";
cin>>coursePTR[count].courseNumber;
cout<<"\nEnter student "<<count+1<<"'s credit hours\n";
cin>>coursePTR[count].creditHours;
cout<<"\nEnter student "<<count+1<<"'s grade\n";
cin>>coursePTR[count].grade;
}
return coursePTR;
}
The pointer to your array is called coursePTR, not courseArray. Just replace the name courseArray with coursePTR.
For this line:
const int *sizePTR = &courses;
You don't have to do that, you can just use courses directly (so, remove all the * from the places you use sizePTR then change sizePTR to courses).
Also I hope you are remembering to delete[] the return value of readCourseArray :)