Dynamic memory allocation to array of pointers to object - c++

I have a class named Student
class Student
{ string name;
unsigned long int ID ;
string email;
unsigned short int year;
public :
Student() // Constructor
string getName(void);
unsigned long int getID(void);
string getEmail(void);
unsigned short int getYear(void);
{
and another class named eClass
class eClass {
private:
string eclass_name;
Student* students[100];
unsigned int student_count;
public:
eClass(string name)
{
student_count =0 ;
eclass_name = name ;
}
bool exists(Student obj)
{
unsigned long int code = obj.getID();
bool flag = TRUE ;
for (unsigned int i = 0 ; i<=student_count ; i++ )
{
unsigned long int st = (*students[i]).getID();
if (code==st)
{
flag = FALSE;
}
}
return flag;
}
void add(Student& obj)
{
bool res = exists(obj);
if (res)
{
students[student_count] = new Student(); //probably the problem is here
*students[student_count] = obj ;
student_count++ ;
}
}
string getEclassName(void) { return eclass_name; }
unsigned int getStudentCount(void) { return student_count; }
Student getStudent(int i) { return *students[i-1]; }
};
The statement Student* students[100]; must look exactly like this . For example I can't write something like this: Student* students[100]={} ;
And main() looks like this
int main()
{
Student JohnDoe("John Doe", 12345, 2, "johndoe#gmail.gr");
eClass Cpp("C++");
Cpp.add(JohnDoe);
}
Basically I have an array of pointers to Student objects and I want to allocate dynamically memory every time I want to add a new Student object.
When I compile I get no errors but when I try to run the program the only thing I get is "Program_name.exe" stopped running...
I'm pretty sure the problem has to do with memory allocation but I'm not able to find it and solve it.
Any suggestions ?

The main bug in exists was the loop went one too far, using an uninitialized pointer. But also it is very bad style for exists to take its input by value. Fixing both of those:
bool exists(Student const& obj)
{
unsigned long int code = obj.getID();
bool flag = TRUE ;
for (unsigned int i = 0 ; i<student_count ; i++ )
{
unsigned long int st = (*students[i]).getID();
if (code==st)
{
flag = FALSE;
}
}
return flag;
}
You should declare getID() const inside student in order to be able to code exists correctly.
unsigned long int getID() const;

First, you should initialize all of your student pointers to either NULL or nullprt. This is not strictly needed but is a very good habit to get into. You'll thank yourself later.
Second, why are you returning false if the student exists? Kind of confusing I'd imagine. Also, you can use the break statement after you find your student exists; no need to check the rest of them.
Also, on your add, you may want to check to ensure you don't have MORE than 100 students. This will overwrite memory and bad things will happen.

Related

How to pass array of object pointers to function?

I am having trouble passing an array of object pointers from main() to a function from different class.
I created an array of object pointers listPin main() and I want to modify the array with a function editProduct in class Manager such as adding new or edit object.
Furthermore, I want to pass the whole listP array instead of listP[index]. How to achieve this or is there any better way? Sorry, I am very new to c++.
#include <iostream>
using namespace std;
class Product
{
protected:
string id, name;
float price;
public:
Product()
{
id = "";
name = "";
price = 0;
}
Product(string _id, string _name, float _price)
{
id = _id;
name = _name;
price = _price;
}
};
class Manager
{
protected:
string id, pass;
public:
Manager(string _id, string _pass)
{
id = _id;
pass = _pass;
}
string getId() const { return id; }
string getPass() const { return pass; }
void editProduct(/*array of listP*/ )
{
//i can edit array of listP here without copying
}
};
int main()
{
int numProduct = 5;
int numManager = 2;
Product* listP[numProduct];
Manager* listM[numManager] = { new Manager("1","alex"), new Manager("2", "Felix") };
bool exist = false;
int index = 0;
for (int i = 0; i < numProduct; i++) { //initialize to default value
listP[i] = new Product();
}
string ID, PASS;
cin >> ID;
cin >> PASS;
for (int i = 0; i < numManager; i++)
{
if (listM[i]->getId() == ID && listM[i]->getPass() == PASS) {
exist = true;
index = i;
}
}
if (exist == true)
listM[index]->editProduct(/*array of listP */);
return 0;
}
Since the listP is a pointer to an array of Product, you have the following two option to pass it to the function.
The editProduct can be changed to accept the pointer to an array of size N, where N is the size of the passed pointer to the array, which is known at compile time:
template<std::size_t N>
void editProduct(Product* (&listP)[N])
{
// Now the listP can be edited, here without copying
}
or it must accept a pointer to an object, so that it can refer the array
void editProduct(Product** listP)
{
// find the array size for iterating through the elements
}
In above both cases, you will call the function as
listM[index]->editProduct(listP);
That been said, your code has a few issues.
First, the array sizes numProduct and numManager must be compiled time constants, so that you don't end up creating a non-standard variable length array.
Memory leak at the end of main as you have not deleted what you have newed.
Also be aware Why is "using namespace std;" considered bad practice?
You could have simply used std::array, or std::vector depending on where the object should be allocated in memory. By which, you would have avoided all these issues of memory leak as well as pointer syntaxes.
For example, using std::vector, you could do simply
#include <vector>
// in Manager class
void editProduct(std::vector<Product>& listP)
{
// listP.size() for size of the array.
// pass by reference and edit the listP!
}
in main()
// 5 Product objects, and initialize to default value
std::vector<Product> listP(5);
std::vector<Manager> listM{ {"1","alex"}, {"2", "Felix"} };
// ... other codes
for (const Manager& mgr : listM)
{
if (mgr.getId() == ID && mgr.getPass() == PASS)
{
// ... code
}
}
if (exist == true) {
listM[index]->editProduct(listP);
}
You cannot have arrays as parameters in C++, you can only have pointers. Since your array is an array of pointers you can use a double pointer to access the array.
void editProduct(Product** listP){
and
listM[index]->editProduct(listP);
Of course none of these arrays of pointers are necessary. You could simplify your code a lot if you just used regular arrays.
Product listP[numProduct];
Manager listM[numManager] = { Manager("1","alex"), Manager("2", "Felix")};
...
for(int i = 0; i < numManager; i++ ){
if(listM[i].getId() == ID && listM[i].getPass() == PASS) {
exist = true;
index = i;
}
}
if(exist == true){
listM[index].editProduct(listP);
}

How can I assign to an int variable something like class.array[i]?

Sorry if my question is basic, but I got stuck.
This is my class.
class FidelityCard {
public:
const int id; //constant attribute - generated based on noCards value
private:
char owner[50];
string cardType; //the service that provides the card (ex. Rompetrol, Mega Image, etc)
int* points = NULL; //points accumulated each time the client buys something
int noPayments; //number of payments done by the client
static int noCards; //incremented for each created card
}
This is the constructor used.
FidelityCard(const char* name, string cardName, int* existingPoints, int noPoints) : id(0) {...}
I'm trying to save in the variable somePoints the value of card3.points[1] using an operator(I think it's operator[]) but I don't know how.
int somePoints[] = { 15,5,10,30 };
int noPoints = 4;
FidelityCard card3("John", "ACME Inc", somePoints, noPoints);
int somePoints = card3[1]; //returns the number of points from the array on index 1
When I'm using this operator
int& operator[](int index)
{
if (index >= 0 && index < noPayments)
{
return points[index];
}
throw new exception("wrong index");
}
I get this error:
Error C2040 'somePoints': 'int' differs in levels of indirection from 'int [4]'
So the obvious (?) problem here
int somePoints[] = { 15,5,10,30 };
int noPoints = 4;
FidelityCard card3("John", "ACME Inc", somePoints, noPoints);
int somePoints = card3[1];
is that you've declared the name somePoints twice. First as an array, then as an int variable.
Just pick a different name for the variable, e.g.
int aPoint = card3[1];

Simplest way to read data from a txt file

I want to store the contents of a .txt file as attributes of different objects which I can then store in a vector. Is there a simple way to do this.
My txt file looks like this:
a0 0 4 0 10
a1 0 3 0 20
a2 0 2 0 30
I tried to do it like this but i get an error.
class process {
public:
std::string name;
int arrivalTime;
int priority;
int age;
int ticketsReq;
int time;
process(std::string name, int arrivalTime, int priority, int age, int ticketsReq) {
this->name = name;
this->arrivalTime = arrivalTime;
this->priority = priority;
this->age = age;
this->ticketsReq = ticketsReq;
this->time = 0;
}
};
int main() {
std::ifstream theFile("input.txt");
int i = 0;
std::vector<process> a;
std::string nameT;
int arrivalTimeT;
int priorityT;
int ageT;
int ticketsReqT;
int timeT;
while(theFile>>nameT>>arrivalTimeT>>priorityT>>ageT>>ticketsReqT){
a[i] = process (nameT,arrivalTimeT,priorityT,ageT,ticketsReqT);
i++;
}
}
Okay, I see at least one problem.
First, vector assumes you call push_back to add elements to the vector. You can do vector[index] to access an element once it exists. But you're going to get a range problem with that.
Second, this line doesn't make sense:
a[i] = process (nameT,arrivalTimeT,priorityT,ageT,ticketsReqT);
At the point you do this, you don't have a "this" for process. You would need to do something like:
process myObj(nameT,arrivalTimeT,priorityT,ageT,ticketsReqT);
a.push_back(myObj);
As a side-point, I personally never store objects in std::vector. I store pointers to objects. I don't know if someone else can comment on this, but consider what happens. You may want to write a simpler example to test that.

Nested structure function in c++

I'm having trouble with one of my assignments (or maybe I'm overthinking it?)
I need to create
a function to take integer parameters for number of students and tests.
Allocate the memory needed for the array of students and the array of test scores for each student.
Return a pointer to the array of Student structures. No display output is done in this function.
int main()
{
int studentNum;
int testNum;
cout << "How many students are there?\n";
cin >> studentNum;
cout << "How many tests are there?";
cin >> testNum;
system("pause");
return 0;
}
my function
GradeBook *initArrays(int s, int t)
{
GradeBook *ptr;
// Allocate the array of Student structures.
ptr = new GradeBook[s];
// Allocate an array of ints (to hold test scores)
// for each element of the array of Student structures.
for (int count = 0; count < s; count++)
{
ptr[count].tests = new int[t];
}
// Return a pointer to the array of structures.
return ptr;
}
edit: I have edited my function, could i get some opinions on that?
if you are writing this in c++, use classes. if i understand correctly, you should create a structure to save a students id,name,or something and a corresponding grade?
something like:
class Test{
public:
int id;
int grade;
Test(int id, int grade){
this->id = id;
this->grade = grade;
}
};
class Student{
public:
int id;
std::string name;
std::vector<Test> tests;
Student(int id, std::string name)
{
this->id = id;
this->name = name;
}
};
int main(){
vector<Student> students;
int studentnum;
for (int i = 0; i < studentnum; i++){
students.push_back(Student(i, "name"));
//insert all tests of the student by calling students[i].tests.push_back(Test(id, grade))
}
}
this way you don't have to allocate memory, which you can easily overlook freeing.
edit:
this is very basic and not a sophisticated solution, as the properties of the classes are all public.
edit 2:
typedef struct Test{
int id;
int grade;
}Test;
typedef struct Student{
int id;
std::string name;
Test * tests;
}Student;
int main(){
Student * students;
int studentnum;
students = (Student*)malloc(sizeof(Student)*studentnum);
for (int i = 0; i < studentnum; i++){
students[i]->id = id;
students[i]->name = "name";
student[i]->tests = (Test*)malloc(sizeof(Test)*numberofgradesofthatstudent);
for (int j = 0; j < numberofgradesofthatstudent; j++)
{
students[i]->tests[j]->id = testid;
students[i]->tests[j]->grade = grade;
}
}
}
this is schematic! new and malloc reserve memory on the heap, do not forget to free everything when you are done with it.
As said a little above, be careful using brackets {} to delimit your blocks.
Secondly,the syntax:
array[studIndex].Tests
supposes that the value array[studIndex] (here an integer) has a member value named Tests. But in this case it doesn't.
Think about your problem: you need to store two values "connected" to one another in a static array. The way I see it, you should try on with two dimensional arrays:
int 2dArray[nbStudents][nbTests];
If you don't want to bother with 2dimensional arrays, you can also try
int 2dArray[nbStudents * nbTests];
But for conveniance, it is often better to use 2d arrays.
Also, think about declaring your array before the for loops in your function.
Then concatenate two for loops as you did and I'll let you think about the rest...

String in struct in struct in C++

So I've to do another exercise. This time I need to define a struct and a 100-elements array, which will store information about the book (title, author, ID number, price) and a simple function which will print info about all of the books stored. I started with that code:
#include <iostream>
using namespace std;
int main()
{
struct name_surname {string name, surname;};
struct book {string title; name_surname author_name, author_surname; int ID; int price;};
return 0;
}
And, well, what now? How can I store this in an array?
You just create an array of type book or name_surname or whatever you want.
Example:
book arr[100];
arr[0].title = "The last robot";
arr[0].ID = 2753;
Tips:
It's good programming practice if your structs/classes begin with with capital letter, so it's easier to distinguish them and so it is easier to name the variable the same name just without the capital letter. Example.
struct Name_surname
{
string name, surname;
};
Name_surname name_surname[100];
name_surname[0].name = "MyName";
Another tip is that I'd really suggest you learn how to research, this question has been answered millions of times and answers are all over the internet.
Here is my suggestion :
struct book
{
string title;
string name_surname;
string author_name;
string author_surname;
int ID;
int price;
};
struct Database
{
book *array;
void printDatabase()
{
for(int i = 0 ; i < 100 ;i++)
cout<<array[i].title<<endl;
}
Database()
{
array = new string [100];
}
};
Your name structure seems a little confused but creating an array is simply a case of declaring a variable with [] appended to it giving the size.
For example:
struct full_name
{
std::string firstname;
std::string surname;
};
struct book
{
std::string title;
full_name author;
int ID;
int price;
};
int main()
{
// Declare an array using []
book books[100]; // 100 book objects
// access elements of the array using [n]
// where n = 0 - 99
books[0].ID = 1;
books[0].title = "Learn To Program In 21 years";
books[0].author.firstname = "Idont";
books[0].author.surname = "Getoutalot";
}
What do you think about that:
#include <iostream>
using namespace std;
struct book {string title; string name; int ID; int price;} tab[100];
void input(book[]);
void print(book[]);
int main()
{
input(tab);
print (tab);
return 0;
}
void input(book tab[])
{
for (int i=0;i<3;i++)
{
cout<<"\nBook number: "<<i+1<<endl;
cout<<"title: ";cin>>tab[i].title;
cout<<"name: ";cin>>tab[i].name;
cout<<"ID: ";cin>>tab[i].ID;
cout<<"price: ";cin>>tab[i].price;
}
}
void print (book tab[])
{
for (int i=0; i<3; i++)
{
cout<<"\nBook number: "<<i+1<<endl;
cout<<"title: "<<tab[i].title;
cout<<"\nname: "<<tab[i].name;
cout<<"\nID: "<<tab[i].ID;
cout<<"\nprice: \n"<<tab[i].price;
}
}
I've done this with help from some Yt video. It works, but, is there a way to do it better, or just leave it how it is? And I have a question: Why those function parameters? Can't I just say tab[] or something else?
Computer languages are based on general and recursive rules. Just try to experiment and extrapolate with the basic understanding to build seemingly complex stuff. Coming to what you are trying to achieve:
We know, an array can be declared for any data-type (primitive or derived, one might call them POD and ADT).
We know, struct can comprise of any number of elements of any data-types.
Now, we can see that it is just as natural to say MyStruct[] as it is to int[].
It is better to prefer std::array if using modern compiler.