C++ dynamic array of pointer to another class - c++

Hello i'm trying to create a dynamic array of pointer to an object Student from Gradesclass but i can't figure out how to declare it in the header
that's the header:
class Grades
{
private:
Student** array;
int _numofStud;
public:
Grades();
Grades(const Grades& other);
~Grades();
and the grades constructor (i'm not sure it's right)
Grades::Grades()
{
this->array = new Student * [2];
for (int i = 0; i < 2; ++i)
{
this->array[i] = NULL;
}
this->array[0]= new Student("auto1", "12345");
this->array[1]= new Student("auto2", "67890");
this->_numofStud = 2;
}
The probleme is that before it even enter to the constructor, it creating me an array of Size 5 in Grades because i have 5 elements in the Student constructor
Student::Student(const char* name, char* id)
{
this->_numofgrade = 0;
this->setName(name);
this->setId(id);
this->_grades = NULL;
this->_average = 0;
}
And i can't add or modify this size
I want to put a default size of Grades to an array of 2 pointers to student object that i'll define as default then i'll have an other methods that add new Students by creating them and adding their pointers to the array
Th problem is i can't change the size of array and i don't understand why
I hope i was clear in my explanation thanks for your help
Edit:
that's the debuger and you can see when it's creating a new object Grades g1
it's creating an array of 5 instead off two
fill the 2 first as i asked for
and the 3 left i have no idea why they have been created and whats inside them

OK, so to be clear, in any actual programs you should use std::vector or other containers, they have a lot of features I ignored here (being templates, supporting move semantics, not requiring a default constructor, etc.), a lot of saftey (what if a constructor throws an exception? What if I do array.add(array[0])?), while still being pretty well optimised for general purpose usage.
And you should also really look at std::unique_ptr, manual new, delete, is generally asking for leaks and other mistakes, in C++ a manual "free" or "delete" of any resource is almost never needed.
Also note in C++ size_t is often used for sizes/lengths of objects and containers.
So the basic idea of a dynamic array is it changes it's size based on current requirements, so Grades() can just start off empty for example.
Grades::Grades()
: array(nullptr), _numofStud(0)
{}
Then when adding a new item, a new larger array is made, and all the existing items are copied (roughly what std::vector::push_back(x) does).
void Grades::addStudent(Student *student)
{
// make a larger array
Student **newArray = new Student*[_numofStud + 1];
// copy all the values
for (int i = 0; i < _numofStud; ++i)
newArray[i] = array[i]; // copy existing item
// new item
newArray[_numofStud] = student;
++_numofStud;
// get rid of old array
delete[] array;
// use new array
array = newArray;
}

Related

Appending struct by reference to an array in C++

How can I implement a function in C++ that appends a struct instance to an array by reference? So that after appending a struct stored in a variable to the array, this variable can be used further to change the instance of array.
pseudocode:
struct St{
int x
}
St* arr;
St a = {0};
append a to arr;
a.x = 1;
//expecting arr[0].x = 1
Here is the C++ code with the film example (see comments describing the problem):
struct Film{
int id;
char* name;
};
void add_film(Film *&films, int &size, Film &film){
if (size == 0)
films = new Film[1];
else
{
Film *tmp = new Film[size + 1];
for (int i = 0; i < size; ++i)
{
tmp[i] = films[i];
}
delete[]films;
films = tmp;
}
films[size] = film;
film = films[size]; //how to reassign passed film object to a new object in array?
size++;
}
int main(){
Film *films = nullptr;
int size = 0;
Film film = {1, "Name1"};
add_film(films, size, film);
film.name = "Name2";
std::cout << films[0].name; //output: "Name1", expected: "Name2"
}
Appending struct by reference to an array in C++
There are two problems with this:
There cannot be arrays of references in C++.
There is no way to append to an array. The size of an array is a constant. There is no way to add or remove elements.
An issue with your attempted solution is that you have an array of Films, and not an array of references. This isn't very surprising, as problem 1 described above states there are no such thing as arrays of references. The solution is simple however: Use pointers instead of references. Technically, you could use a reference wrapper instead, but a pointer is often simpler.
You've basically figured out the solution to 2. already. What you're doing is creating a new array, copying the old elements from the old array into the new one, and destroying the old array. That's a good approach in general, but there are a number of problems with this trivial implementation:
Bare owning pointers are unsafe and hard to use.
Reallocating and copying the entire array on every append is very expensive.
Former can be solved by using the RAII idiom, and latter can be solved by separating the storage of the objects from the creation of the objects, and by growing the storage by a constant factor i.e. geometrically. There is no need to implement such RAII container though, since the standard library has you covered. It's called std::vector.
In conclusion: You can use std::vector<Film*>.

Set one element in Array to nullptr

new to C++ for a school project and I cannot seem to get past this final part of my project.
I have a class "Roster" that has an array of object pointers
Student* classRoster[MAX_ROSTER] = {};
These "Student" objects have been dynamically added to the array with a Roster method that does:
classRoster[arrayLength++] = new Student(...);
Where
#define MAX_STUDENTS 5
int arrayLength = 0;
The goal is to remove a specific student from the array but keep the others. The function looks something like this:
for (int i = 0; i < MAX_STUDENTS; i++) {
if (classRoster[i]->getID() == studentID) {}
}
Now inside this function I have tried a number of different things, delete the memory and set the pointer to null, attempt to delete the memory and re-arrange the array, but nothing seems to work.
I found this question with an accepted answer: Set array of object to null in C++, but that isn't working for me and I cannot figure out why.
I have set a bool and position int in the function before the loop and tried removing the student after identification, removing in the loop etc.
I assumed this would be correct:
delete[] classRoster[i];
classRoster[i] = nullptr;
(Where i is the matched student) But this deletes the memory for all the elements in the array and if I just try
classRoster[i] = nullptr;
that makes all the elements after "i" also nullptr.
delete* classRoster[i];
gives an error that we cannot delete type 'Student'
and
delete classRoster[i];
does nothing since the array doesn't have objects but pointers to objects.
What am I doing wrong?

how can I copy an array from a class and double the size of the new array?

CDCatalogue::CDCatalogue() //creates array of size 4
{
maxsize=4;
numcds = 0;
cds = new CD[maxsize];
}
I want this to copy cat into a new array with double the size of cat:
CDCatalogue::CDCatalogue(const CDCatalogue& cat)
{
}
As suggested before I'd prefer to use std::vector, which offers the resize() member function for exactly what you need. This is probably what you are looking for.
If for some reason you cannot use vectors, maybe a simpler approach than having a "doubler copy constructor" would be having a function 'doubleSize' that you can call right after construct-copying.
Assuming that in your example in the question, maxsize and cds are declared as class members, you could do something like this:
CDCatalogue::doubleSize() {
unsigned int oldMaxSize = maxsize;
maxsize *= 2; // You might want to keep an eye for overflows here
CD *oldCds = cds;
cds = (CD*) new CD[maxsize];
std::copy(oldCds, oldCds+oldMaxSize, cds);
delete[] cds;
}
Note that this is not as simple as using vectors, because there is no "resize" for c++ dynamic allocations. Instead, you have to create a new array of the new desired size, copy the elements of the old array into the new, and then release the memory of the old array. Note that the last half of elements of the new array will be initialized to undefined values.

How to use a dynamically resizing String Array?

I'm trying to use an array in C++ that changes in size. For some reason the size does not change, it only ever holds 1 string. The difficult part is that the user cannot input the number of courses they are going to add, instead the addCourse function is called until the user stops. A vector cannot be used (this is for a school assignment, and a resizing array is required). I'm stuck as to why the array only seems to hold one string, I would think it to hold the equivalent of numCourses strings. How would I go about resizing to hold multiple strings after each call to the function?
void Student::addCourse(string* courseName)
{
int x;
numCourses += 1;//increments number of courses
string newCourse = *courseName;
string* newCourses = new string[numCourses];//temporary array
for(x=0; x<numCourses - 1; x++)//fills temp array with the values of the old
{
newCourses[x] = courses[x];
}
newCourses[numCourses - 1] = newCourse;//adds extra value
delete[] courses;//removes original array
courses = newCourses;//sets the new course list
}
Edit: For those asking why a vector cannot be used because the point of the assignment is to actively avoid memory leak using the heap. Using an array like this forces intentional delete of stored values.
The comment should have answered your question: there is no way for the debugger to know that a pointer to a string is pointed to an array, nor does it know its bounds, because no such information is kept at runtime (a std::vector will show its whole contents in the debugger, in contrast).
Your method prototype should read:
void Student::addCourse(const string& courseName);
If you don't want to have a memory leak, declare a pointer to courses in your class:
private:
string* courses;
Allocate space for an array of strings in your constructor:
Student::Student()
{
courses = new String[5];
}
Then deallocate in the destructor:
Student::~Student()
{
delete[] courses;
}
This gives you room for up to 5 courses. If you need more you need to adjust the size of the array of strings at run time:
void Student::ExtendArray()
{
delete[] courses;
courses = new String[10];
}
Note this code is not exception safe, but will give you the basic idea.

possible problems after resizing dynamic array

Got little problem here.
I created dynamic array:
m_elements = new struct element*[m_number_of_elements];
for(int i = 0; i < m_number_of_elements; i++)
{
m_elements[i] = new struct element[m_element_size];
}
then I tried to resize existing array:
m_elements[m_number_of_elements] = create_more_elements();
m_number_of_elements++;
create_more_elements() is a function:
struct index* create_more_elements()
{
struct element* tmp = new struct element[m_number_of_elements]
return tmp;
}
In general, this piece of code works, but sometimes I get segfaults in different places.
Are segfaults connected with resizing?
Any thoughts?
You should use std::vector for it, then you can with new allocate memory for new struct and push her pointer to vector, if you deleting you should delete on pointer.
Try this:
std::vector<element> m_elements;
m_elements.resize(m_number_of_elements);
Don't go the route of manually managing an array unless absolutely necessary - std::vector will do a far better job, is better tested, proven, standardized and understood by legions of C++ programmers. See my code example - not even a single new or delete statement, yet this code also contains all required memory management.
P.S.: Since this question is tagged as C++, you don't have to write struct element whereever you use it as a type, just element will suffice. This suggests you are coming from C, so my advice: learn about the STL before you continue what you're doing, a single hour spent learning how to use the standard container classes can save you many days of manual tweaking, debugging and bug-fixing. Especially since once you've learnt one, you already know like 80% about all the others. :)
m_elements[i] = new struct element[m_element_size];
This creates an array of element of size m_element_size
To dynamically create a struct, just use new struct element or new element.
If don't have to initialize values in your array, you may even be better not storing pointers but actual objects in your array:
m_elements = new element[m_number_of_elements];
To "resize" an array, you actually have to allocate a new bigger array, copy the content of current array in the new one, and delete the old array.
// Allocate new array
element* newArray = new element[m_number_of_elements + 1];
// Copy old array content into new one
memcpy(newArray, m_elements, m_number_of_elements * sizeof(element)];
// Delete old array
delete[] m_elements;
// Assign new array
m_elements = newArray;
// Keep new size
m_number_of_elements += 1;
But you should definitely use std::vector which is simpler and smarter than that:
std::vector<element> elements;
// Add an element
Element element;
...
elements.push_back(element);
It is a wonder that you code even works. Basically what you are doing is overwriting memory after your initially allocated array. In C++ you can't resize the array, you can only delete it and new up a new one.
element** tmp = new element*[m_number_of_elements];
for(int i = 0; i < m_number_of_elements; i++)
{
tmp[i] = m_elements[i]
}
delete m_elements;
m_elements = tmp;
m_elements[m_number_of_elements] = create_more_elements();
m_number_of_elements++;
But, that is really crufty. As Svisstack points out, you should use std::vector or any other suitable standard container.
std::vector<element*> m_elements;
// ...
m_elements.push_back(create_more_elements());