Pointer as a structure members - c++

struct student{
string name;
int sNumber,*examGrade;
};
int main(){
int i,k,l;
cout<< "number of student in program:";
cin >>l;
cout<< "number of exam in program:";
cin >>k;
student stName[100], examNum[100];
for(int i=1;i<=l;i++){
student stdnt;
cout<<i<<".student name: ";
cin>>stdnt.name;
cout<<i<<".student number: ";
cin>>stdnt.sNumber;
stName[i] = stdnt;
for(int j=1 ; j<=k; j++){
student * test = new student();
cout<<i<<". student"<<j<<".grade: ";
cin>>*test->examGrade;
examNum[j]= *test;
}
}
return 0;
}
I just started coding. What is the reason why the function could not be completed in the code I wrote?
How to assign value to a pointer struct?
I think I made a mistake accessing the pointer to the struct members.

You used test->examGrade without initializing that. Assign valid pointer to that before dereferencing that.
for(int j=1 ; j<=k; j++){
student * test = new student();
cout<<i<<". student"<<j<<".grade: ";
test->examGrade = new int; // add this, for example
cin>>*test->examGrade;
examNum[j]= *test;
}

Related

Increasing class pointer array

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.

What is the necessity of pointer in this piece of C++ code?

Note - I have searched a lot on pointers and references for C++.
I don't seem to understand them in THIS particular scenario. Hence posting it here!
The following is CORRECT code. It is working. I wrote this for an online C++ practice problem. A part of the code was given to me initially.
I don't understand why an array of Person objects is being created in the main function with a *per[n] as shown below:
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
class Person {
string name;
int age;
public:
Person(){
name = "";
}
virtual void putdata() = 0;
virtual void getdata() = 0;
};
class Professor: public Person {
int publications, cur_id;
string name;
int age;
public:
static int professorCount;
Professor(){
name = "";
age = 0;
publications = 0;
cur_id = professorCount + 1;
professorCount++;
}
void getdata(){
cin >> name >> age >> publications;
}
void putdata(){
cout << name << " " << age << " " << publications << " " << cur_id << endl;
}
};
class Student: public Person {
int marks[6];
int cur_id;
string name;
int age;
public:
static int studentCount;
Student(){
name = "";
age = 0;
cur_id = studentCount + 1;
studentCount++;
}
void getdata(){
cin >> name >> age >> marks[0] >> marks[1] >> marks[2] >> marks[3] >> marks[4] >> marks[5];
}
void putdata(){
cout << name << " " << age << " " << marks[0] + marks[1] + marks[2] + marks[3] + marks[4] + marks[5] << " " << cur_id << endl;
}
};
int Professor::professorCount = 0;
int Student::studentCount = 0;
In this main function below, an array of Person objects is being created, but it is given a * in the beginning. How is it working?
int main(){
int n, val;
cin>>n; //The number of objects that is going to be created.
Person *per[n]; // THIS ONE RIGHT HERE! THIS ONE!
for(int i = 0;i < n;i++){
cin>>val;
if(val == 1){
// If val is 1 current object is of type Professor
per[i] = new Professor;
}
else per[i] = new Student; // Else the current object is of type Student
per[i]->getdata(); // Get the data from the user.
}
for(int i=0;i<n;i++)
per[i]->putdata(); // Print the required output for each object.
return 0;
}
I don't understand why an array of Person objects is being created in the main function with a *per[n] as shown below
The purpose of storing a pointer is to support virtual polymorphism (abstract classes like Person cannot be instantiated). A smart pointer serves that as well, but takes care about the correct dynamic memory management.
There's no need to use raw pointers or raw arrays in c++ at all. That code doesn't give a good example of "best practices".
At the main() function
Person *per[n]; // Note that VLA's aren't standard c++ syntax
should be replaced with
std::vector<std::unique_ptr<Person>> per(n);
and the loop accordingly
for(int i = 0;i < n;i++){
cin>>val;
if(val == 1){
// If val is 1 current object is of type Professor
per[i] = std::make_unique<Professor>();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
// Else the current object is of type Student
else per[i] = std::make_unique<Student>();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
per[i]->getdata(); // Get the data from the user.
}
Also
int marks[6];
should be replaced with
std::array<int,6> marks;
std::array is way more convenient and less error prone when passed as function parameter, etc.
You're creating an array of pointers to Person objects. That's how assignments like per[i] = new Professor; can work - new Professor returns a pointer to a Professor object, so you need an array of pointers to store that.

Changing value of element in dynamically allocated array

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);
}
}

c++ pointer to a Structure whose member is a pointer

Hi all I am working on an assignment , when given a struct and its members I will have to intialise the members using dynamic memory allocation . This is the code I have used:
# include <iostream>
# include <string>
using namespace std;
Structure
struct Student
{
char * name;
float gpa;
} ;
PROTOTYPES
Student * createStudent(char name[], float gpa);
int main ()
{
int length ;
float gpa ;
char *p;
Student *myPointer ;
Student myStudent ;
myPointer = &myStudent;
cout << " Please enter number of characters you want to enter " << endl;
cin >> length ;
length = length + 1;
p= new char [length +1];
cout << " Please enter name " << endl;
cin >> p ;
cout << " please enter gpa "<< endl;
cin >> gpa ;
myPointer = createStudent (p,gpa);
cout << myPointer->gpa;
cout << (*myPointer).name << endl;
Her's the error when printing the name, but when i see the value of the name before printing it is showing the same as entered by the user:
delete[]p;
p = 0;
system("pause");
return 0;
}
This function creates a student object and assigns name and gpa as passed to the student object and returns a pointer of the student object:
Student * createStudent( char name[], float gpa )
{
Student *studentPtr ;
Student studentObject;
studentPtr = &studentObject;
studentPtr-> name = name;
studentPtr-> gpa = gpa ;
return studentPtr ;
}
Can anyone give me an idea of why the name is not printing. Thank you in advance .
studentObject is allocated on the stack, i.e. it has automatic storage duration, which means it will be destroyed when the function returns. The pointer doesn't keep it alive.
That means myPointer is a dangling pointer; dereferencing it (myPointer->) invokes undefined behavior.
To correct it, simply return the object by value:
Student createStudent(char name[], float gpa)
{
Student studentObject;
studentPtr.name = name;
studentPtr.gpa = gpa;
return studentObject;
}
and
Student myStudent = createStudent(p, gpa);
Edit: I just read that you need to initialize the members using dynamic memory allocation. The above solution doesn't do that. For dynamic memory allocation you have to use new:
Student* createStudent(char name[], float gpa)
{
Student* studentPtr = new Student;
studentPtr->name = name;
studentPtr->gpa = gpa;
return studentPtr;
}
and
myPointer = createStudent(p, gpa);
// use
delete myPointer;
It would probably be a good idea to also allocate a new buffer for studentPtr->name with new, instead of just assigning the pointer; you can see Mateusz's answer about that.
But of course this is just a bad example from your professor. As mentioned by gd1, this kind of code is not good modern C++ and shouldn't end up in real production code.
This is totally wrong:
Student* createStudent( char name[], float gpa )
{
Student *studentPtr ;
Student studentObject;
studentPtr = &studentObject;
studentPtr-> name = name;
studentPtr-> gpa = gpa ;
return studentPtr ;
}
studentObject is a local object, that is destroyed just after the function ends. Returning pointers and/or references to local variables is an error - you should get warning from your compiler.
Another issue is this line:
studentPtr->name = name;
What you do now: allocate a block of memory in main(), pass it to an object, that may use this memory and then free it in main(). You should not do that - objects should be responsible for their content. Are you sure, that this responsibility should be yours? I would suggest you to:
Student* createStudent( char name[], float gpa )
{
size_t name_len = strlen(name);
Student studentObject;
studentObject.name = new char[name_len+1];
strncpy(studentObject.name, name, name_len + 1);
studentObject.gpa = gpa ;
return studentObject;
}
And analogical function to destroy Student:
void destroyStudent(Student* student)
{
delete[] student->name;
student->name = nullptr;
}
Obvious solution would be to use std::string, but I assume, that you have a good reason to do all this manually... don't you?
Oh, and if you really need to return Student as pointer:
Student* createStudent( char name[], float gpa )
{
size_t name_len = strlen(name);
Student* studentPtr = new Student;
studentPtr->name = new char[name_len+1];
strncpy(studentPtr->name, name, name_len + 1);
studentPtr-> gpa = gpa ;
return studentPtr;
}
void destroyStudent(Student* student)
{
delete[] student->name;
student->name = nullptr;
delete[] student;
}

Reading into dynamically created pointer to array of structs

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;
}