char array corruption in C++ - 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);
}

Related

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?

Why does the array length change when an array that contains a pointer is a parameter of a method?

I have a Node class, and when I created an array of Node pointer(Node*) and passed it through the method, I had a different length of the array as the parameter.
Node* hands[4];
Deal(deck,hands,4,"one-at-a-time",13);
void Deal(Node* &deck, Node* hands[], int people, std::string type, int count){
Node*& temp = deck;
for (int i = 0; i < count; ++i) {
for (int j = 0; j < people; ++j) {
append(hands[j], CopyDeck(temp));
temp = temp->after;
}
}
}
When I use Clion debugger to see the value of variables, I found that hands that I create has values of
hands[0] = 0x746365667265700e
hands[1] = NULL
hands[2] = NULL
hands[3] = 0x00007fc44b402430
And when it is passed through the method, in method the hands is
*hands=0x746365667265700e
hands[1]=NULL
hands[2]=NULL
hands[3]=0x00007fc44b402430
hands[4]=0x00007fc44b402570
What does the "*hands" stand for? And why the initial value in hands are not NULL? Actually the minimal example I can have is something like:
class Node{};
void test(Node* list[]){}
int main(int argc, char* argv[]){
Node * temp[4];
test(temp);
}
But it works. And I have already written the same code in other files and works as I thought.
The deck is a simply doubly-linked list of Node. Node has an attribute "after" point to the next Node. My debugger told me before
Node* &temp = deck;
the parameter "hands" already becomes a 5 elements array.
I think I found a possible reason but I can't understand the relationship between. There are two test methods in my main function. The first one is called "SortingTest" and the second one is "DealingTest". When I comment the first test method out, my DealingTest works properly, but after I uncomment it, the DealingTest doesn't work. After SortingTest ends there is no attribute or anything left in the main method. Can anyone explain it to me? Thank you all. Or maybe my clear method is wrong so it not frees the memory correctly?
void DeleteAllCards(Node* root){
Node *current, *next;
current = root;
while (current != nullptr){
next = current->after;
delete current;
current = next;
}
}
The array you created is a C-Style array, which is a fixed size array with 4 elements. In your case, the element type is Node pointer.
C-Arrays do not initialize with default values, unlike many other popular languages. Therefore, the pointer values you are seeing in hands are either a pointer to a Node * or derived type or a garbage memory address with some exceptions to this rule (see below for the edge cases defined by the Standard. For the ones that do say NULL, their memory address is at ox0000...
Update Edit To reflect a comment made by #AlgirdasPreidZius -
For C and C++, there is a standard rule where a standard C-Array shall be populated with default values upon initialization. C++ standard section 6.8.3.2.2 ([basic.start.static]): "If constant initialization is not performed, a variable with static storage duration or thread storage duration is zero-initialized."
As to why your array has those values in them from the function provided, we need more context. A reproducible example is always the best.
Your for loop, judging by the passed in parameters, is an N^2 time complexity loop with 4*4 iterations. The C-Array Node * was also passed in by reference, so when you assign Node *& to deck, the memory address marking the start of the array changes to the location of the deck array. So, it will have the values that the deck C-Array of Node *'s contains, assuming copy is a 1 : 1 copy, deep or shallow

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.

Variable as reference not staying

So i read this thread and many others:
Function does not change passed pointer C++
Yet i still can't solve my issue.
I have a function declared like this:
void test(list<int*> *listNodes){
int v=5;
(*listNodes).push_back(&v);
(*listNodes).push_back(&v);
(*listNodes).push_back(&v);
for(int a = 0; a < (*listNodes).size(); a ++){
std::list<int*>::iterator i = (*listNodes).begin();
advance(i, a);
int *totry = *i;
cout << *totry;
cout << ",";
}
}
Wich works, and prints fine, by the i mean: the listNodes variable has 3 elements, all 5's. However, when this functions returns, the values are not updated. By that, i mean that the variable has trash. I call this function in another one like this:
void create(list<int*> listNodes){
test(&listNodes);
for(list<int*>::const_iterator it=listNodes.begin();
it!=listNodes.end(); it++){
int *show=*it;
cout << *show << '\n';
}
}
Again, in this function, the cout will output memory garbage instead of outputting the 3 fives.
Any ideas on how should i proceed to, when the function test comes back, i have the list populated?
The problem I believe you're thinking about (as opposed to other problems in this code) is not actually what you're thinking. The list DOES maintain its values, the problem is that the values it has are pointing to garbage memory.
When you do this:
int v=5;
(*listNodes).push_back(&v);
(*listNodes).push_back(&v);
(*listNodes).push_back(&v);
You are putting three copies of the address of v into the list. You have declared v as a stack variable that only exists for the duration of this function. When you print the values pointed to by the elements of listNodes inside function test, that variable still exists in that memory location.
When you later print out the values pointed to by the elements of listNodes in function create, that variable has gone out of scope and has been used by something else, hence the garbage.
Here are two possible solutions to consider:
Use list<int> instead of list<int *>. If all you want to do is store a list of integers, this is the way to go.
If, on the other hand, you really need to store pointers to those integers, you'll need to allocate memory off the heap:
int* v = new int(); // allocate an int on the heap
*v = 5; // store 5 in that int
(*listNodes).push_back(v); // save the pointer to the allocated
// memory in *listNodes
etc
This is not very good in terms of modern c++, however, as you generally don't want to be handling raw pointers at all, but it illustrates the point I think you are struggling with.
In this code,
void create(list<int*> listNodes){
listNodes=teste(&listNodes);
… the formal argument listNodes is passed by value. That means that the function receives a copy of whatever was passed as actual argument in a call siste. Changes to this copy will not be reflected in the actual argument.
The call to teste won't call the test function, since it's a different name.
In a way that's good, because test is declared as a void function so it can't return anything.
But it's also bad, because it means that a very crucial piece of your code, the teste function that's actually called, isn't shown at all in your question.
The test function,
void test(list<int*> *listNodes){
int v=5;
(*listNodes).push_back(&v);
for(int a = 0; a < (*listNodes).size(); a ++){
std::list<int*>::iterator i = (*listNodes).begin();
advance(i, a);
int *totry = *i;
cout << *totry;
cout << ",";
}
printf("\n");
}
… has a lot wrong with it.
Starting at the top, in C++ the pointer argument
void test(list<int*> *listNodes){
… should better be a pass-by-reference argument. A pointer can be null. That doesn't make sense for this function, and the code is not prepared to handle that.
Next, in
int v=5;
(*listNodes).push_back(&v);
… the address of a local variable is pushed on a list that's returned. But at that point the local variable ceases to exist, and you have a dangling pointer, one that used to point to something, but doesn't anymore. If the caller uses that pointer then you have Undefined Behavior.
Next, this loop,
for(int a = 0; a < (*listNodes).size(); a ++){
std::list<int*>::iterator i = (*listNodes).begin();
advance(i, a);
… will work, but it needlessly has O(n2) complexity, i.e. execution time.
Just iterate with the iterator. That's what iterators are for. Iterating.
Summing up, the garbage you see is due to the undefined behavior.
Just, don't do that.