Set one element in Array to nullptr - c++

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?

Related

C++ dynamic array of pointer to another class

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

Problem implementing a dynamically-sized array

I'm writing an implementation of a dynamically-sized array. The code compiles without errors, but the array elements don't get copied properly. They seem to just get erased (overwritten with 0's). Trying to call a getter on an array element causes a segfault.
The array holds pointers to some basic class objects; this is the main difference between my code and the examples I looked up.
This is the function:
// Pointer to array of pointers
SomeClass** mainArray = new SomeClass[1];
int numItems = 0;
void AddItemDynamic(SomeClass* newVal) {
SomeClass** tempArray = new SomeClass*[numItems+1];
// Copying pointers to bigger array
for (int i = 0; i < numItems - 1; i++) {
tempArray[i] = mainArray[i];
}
numItems++;
// Adding the new value
tempArray[numItems] = newVal;
delete [] mainArray;
mainArray = tempArray;
}
The code should copy the array elements over, then reassign the pointer to the newly created array. Instead, the pointer seems to be set to something else.
If the current array have numItems element in them, then the loop
for (int i = 0; i < numItems - 1; i++)
will copy one less than numItems elements.
And when you add the new element, you go out of bounds of the new array, because you increase numItems to early.
So two off-by-one errors in the same function, one in each direction.
And as mentioned in a comment (thanks Ayxan) the first off-by-one error will mean that the first two times you call this function, the copying loop won't happen. That's actually good when doing it the first time as then there's nothing to copy, but the second time there should be something to copy and yet the loop (currently) won't run.

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.

How to remove elements from dynamically allocated array?

I have a dynamically allocated array :
myRectangle lastRectanglesArray = new myRectangle[lastMaxLabel];
I would like to loop through all elements in this array and remove these that will meet my condition (e.g. too big rectangle).
I have been thinking that I can loop through this array and get the number of elements that would satisfy my condition and then allocate a new array. But how can I 'transfer' these 'wanted' elements into my new array ?
Just for the record: I cannot use STL containers.
myRectangle * lastRectanglesArray = new myRectangle[lastMaxLabel];
// initialize the entries in the lastRectanglesArray
// create a temporary array which contains info about each individual
// entry. namely, it only holds info about whether the entry should
// be kept, or deleted.
// we also use the 'entries' value, which is the number of entries
// in the new array
bool * entriesToKeep = new bool[lastMaxLabel];
int entries = 0;
// check each entry, and mark whether it should be kept or deleted
for (int i = 0; i != lastMaxLabel; ++i) {
// check whether the entry should be kept or deleted...
// here, i just put a function with signature like:
// bool shouldKeepRectangle(const myRectangle &);
entriesToKeep[i] = shouldKeepRectangle(lastRectanglesArray[i]);
if (entriesToKeep[i]) ++entries;
}
// create a new array that will contain the entries that should be kept
myRectangle * rectanglesArray = new myRectangle[entries];
// assign the entries in the new array
for (int i = 0, j = 0; i != lastMaxLabel && j != entries; ++i) {
if (entriesToKeep[i])
rectanglesArray[j++] = lastRectanglesArray[i];
}
// free the memory held by the temp array
delete [] entriesToKeep;
// if the old array is not needed anymore, delete it
delete [] lastRectanglesArray;
// and here you have rectanglesArray, a brand new array that contains
// only the elements that you need.
Just move the next array location over the one that needs to be deleted, and shift everything over til the end of the array.
Yours look like the perfect case for using a Linked List. You would however have to do away with the new myRectangle[lastMaxLabel] part as you would have to implement it as pert of your Insert() function.
This way you would not require to transfer the wanted elements into a new array, but just delete the unwanted element.
Any more light on your use-case would help us to think of better alternatives.
I agree with Michael Chinen - use std::vector instead. You'll avoid lots of other potential problems this way. If you really want to use dynamic arrays, see this question: Remove an array element and shift the remaining ones
if you have a big amount of data in array that will be a problem for shifting using loop
maybe you should build your own array management class (find,add,deleteAt,etc).
my suggestion use link list node method.. it will be faster rather then you use loop for shifting.

char array corruption in C++

I'm working on a project that makes me store an array of objects whose constructor is
Item(char* item, int itemType){
char temp[200];
for(int i = 0; i < 200; i++){
temp[i] = '\0';
if(item[i] != '\0'){
temp[i] = item[i];
}
}
_item = item;
_itemType = itemType;
_tweetIDs = NULL;
}
Don't worry about _tweetIDs, that's another functional part of my program and isn't related to my problem.
This array is stored within a class:
ItemList()
How this works is that the functional part of my program parses a line of input and puts it into the Item(char*, int) object. This is how it adds the line:
int addItem(char* item, int type){
char temp1[200];
for(int i = 0; i < 200; i++){
temp1[i] = '\0';
}
int j = 0;
while(item[j] != '\0'){
temp1[j] = item[j];
j++;
}
_items[_size] = Item(temp1, type);
_size++;
return _size;
}
Where _items is the Item() array and _size is a field that is incremented every time an Item() is added.
My issue comes when I have to print the contents of the list.
I have a method that does that:
void printList(){
for(int i = 0; i < 500; i++){
if(_items[i] != NULL){
cout << "[" << i << "] ";
_items[i]->printContents();
}
}
}
I tested printContents() in the constructor of Item() and tested printList in the addItem method and they both work when called within the class itself. The issue comes when I have to call the print method outside the class body.
In the main method, I create a List object:
List itemList;
The default constructor sets all members of the Item() array to NULL and initializes _size.
After adding a few Item() objects into the array (Which I confirmed is increasing in size through the debugger), I tried to print it out. When I call:
itemList.printList();
It gives me the right amount of indexes (And lines), but the char array is just a bunch of garbage. I used the debugger to try and find out where it went wrong. In the addItem() method, I called printList to check the array, and the output from that is fine. Then, I called itemList.printList() right after the last addItem() call, and it gave me garbage. In between the addItem() and itemList.printList(), the char array is lost or something along those lines.
Any idea what's going wrong? I'll give you any more code if you need it.
In your Item constructor, you are setting what I presume is a member _item as such:
_item = item;
This just assigns the pointer value of the location pointed to by item into _item. It does not actually copy the string!
The next time you go to read this location, it might be valid - chances are, though, it will be garbage, as you are seeing.
What you are looking for is a function like strcpy (as a side note, there's no need to do quite so much manual copying - just pass that pointer around and copy it once - in the Item constructor).
EDIT, to address your comment:
strcpy made your program crash because you are using it on unallocated memory.
You have to allocate memory for an array using new[] in c++
Take note on the lifetime of a variable.
If you declare temp1 as static array, then it will be destroyed immediately by the end of function addItem.
At the end, all object that refers to this memory location will be invalid.
And ....
If you want to pass a reference to an array do it this way:
Item(char** item, int itemType)
I'm imagining your definition of class Item minimally looks like this:
class Item
{
Item(char* item, int itemType);
private:
char *_item;
};
Your constructor must allocate memory for _item in order to make a copy of what gets passed in via the constructor. Failure to do that will inevitable result in memory problems and exceptions. Alternatively, you can use something like a vector of char.
In Item constructor you create local array char temp[200], you copy there what is pointed by char * item and then you don't use temp[200] any more. What's the point of doing that?
Later you assign passed pointer to _item member. The pointer points to local variable char temp1[200] in addItem(). When addItem() finishes then temp1 is destroyed and so _item in Item class points to garbage.
What you probably need to do is to allocate memory either statically in _item definition or dynamically using new (and then not forget to release it). I think the first solution will be safer for you. In the latter case you would also have to take care of copy constructor and assign operator. So, you need to change _item definition from char * _item to char _item[200], and then you can use strncpy:
Item(char* item, int itemType) {
strncpy(_item, item, 200);
}