Reallocation of Array of Pointers in C++, using new and delete only - c++

Carray.h
#ifndef CARRAY_H
#define CARRAY_H
#include "Cell.h"
#include "Pirate.h"
class CArray
{
public:
CArray();
~CArray();
int getSize();
Cell* get(int);
int add(Cell*);
private:
int size;
Cell** elements;
};
#endif
CArray.cc
CArray::CArray() : size(0)
{
elements = new Cell*[size];
}
CArray::~CArray()
{
for (int i=0; i<size; ++i)
delete elements[i];
}
int CArray::add(Cell* cell)
{
Cell** tmp = new Cell*[size];
tmp = elements;
elements = new Cell*[size+1];
for (int i = 0; i < size; i++){
*(elements + i) = *(tmp + i);
}
*(elements + size) = cell;
delete [] tmp;
size++;
}
This last function gives a memory leak and I'm not sure as to where. All I know is that each new must be matched with a delete and each new[] with a delete[]. However testing this in valgrind and trying to delete[] elements before I reallocate elements gives me a Segmentation Fault. If someone could explain where I'm going wrong I would be a happy camper. I'm sorry if this is a duplicate, but I couldn't find anything specific enough to solve my problem.

You are allocating for tmp and then immediately losing the pointer returned to you by assigning to tmp:
Cell** tmp = new Cell*[size];
tmp = elements;
The lines above produce a memory leak, since the value returned by new is lost as soon as the second line is executed.
All I know is that each new must be matched with a delete and each
new[] with a delete[].
That is not the only thing to consider. The value returned by new/new[] must be the same value you use when calling delete/delete[].
To fix your function, you should do this:
int CArray::add(Cell* cell)
{
Cell** tmp = new Cell*[size + 1];
for (int i = 0; i < size; i++)
tmp[i] = elements[i];
tmp[size] = cell;
++size;
delete [] elements;
elements = tmp;
return 1;
}
Note how the elements are copied to the tmp array, then it's just a matter of simply getting rid of the old memory (which is elements) and assign to elements the new data.
Also, there is another subtle bug in that you have a return value of int, but you didn't return anything. Not returning a value from a function that says it returns a value is undefined behavior.

In the two first lines
Cell** tmp = new Cell*[size];
tmp = elements;
You allocate memory, take direction of new in tmp and replace pointer. So, you lost the direction of new.

Related

why am I consistently getting malloc errors when I try to delete my 2D array made using pointers?

I'm trying to delete my 2D array, but I consistently get errors when I try to delete it, we have to work backwards so I delete the elements first, then the column array, then the row array. here is my code for the constructor in my class, MyMatrix:
private:
int m; //rows
int **ptr; //ptr to first dimension
int n; // columns
public:
MyMatrix() //constructor
{
m = 0;
n = 0;
ptr = new int*[m];
int *length_arr = new int[m];
for (int i = 0; i <= m-1; i++)
{
*(ptr+i) = new int[n];
*(length_arr+i) = n;
}
}
and my destructor looks like this:
for(int i = 0; i <= m-1; i++)
{
for (int j = 0; j <= n-1; j++)
{
delete ((*(ptr+i))+j);
}
delete[] *(ptr+i);
}
delete[] ptr;
the error I'm getting is:
assg7(2677,0x100de3d40) malloc: *** error for object 0x12d606804: pointer being freed was not allocated
I've wracked my brain for where I can fix this, for context, I'm doing an assignment with operator overloading. I specifically need a delete function to work properly for my = assignment overloading since I want to delete and again reallocate memory to equate two matrices, but the terminal is showing malloc errors and is thus not equating the matrices.
for additional info here is my = overloading code:
void operator = (const MyMatrix &obj)
{
if(n == obj.n && m == obj.m)
{
//for loop to equate elements in this-> to the elements of the passed object
}
else
{
for(int i = 0; i <= m-1; i++)
{
for (int j = 0; j <= n-1; j++)
{
delete ((*(ptr+i))+j);
}
delete[] *(ptr+i);
}
delete[] ptr;
// the code for assigning new memory according to the passed objects rows and colums goes here
//then for loop to equate elements in this-> to the elements of the passed object
}
}
thanks.
You have two "levels" of new, so three "levels" of delete can't be right.
Spell out your deletion loop, using indexing instead of pointer arithmetic:
First iteration:
delete ptr[0]+0;
delete ptr[0]+1;
...
delete ptr[0]+n-1;
delete [] ptr[0];
Second iteration:
delete ptr[1]+0;
delete ptr[1]+1;
...
delete ptr[1]+n-1;
delete [] ptr[1];
You're passing to delete a pointer to the first element of ptr[0], a pointer to the second element of ptr[0], a pointer to the third element of ptr[0], ...
But the things you allocated were ptr[0], ptr[1], ... ptr[m-1], not their individual elements.
Remove the innermost deletion loop.
(And don't mess around with pointer arithmetic when you can use indexing.)
I don't know how you would want to allocate memory space by m length if it is set to 0 by default.
To me it looks like you set m = 0 and then try to allocate by 0 length or how do you control the length of your dimensions?
Maybe edit your constructor to:
MyMatrix(int m, int n)
{
this->m = m;
this->n = n;
...

How do I solve this memory leak

I am trying to recreate the vector class and I believe there is a memory leak in my code, but I don't know how to solve it. Using the CRT Library in my Visual Studio, it tells me that there is a supposed memory leak that doubles for each time that reserve is called.
I am not quite sure why that is or if there even is a memory leak. The memory leak detection says that it is this line in the reserve function int* temp = new int[n];
This is what I understand to be happening in the reserve function:
Once the contents of arr are copied into temp, it's fine to delete arr. Assigning arr = temp should work because all I'm doing is making arr point to the same place as temp. Because arr was previously deleted, I only have 1 array in the heap and arr and temp both point to the same array so there should be no memory leak. Temp shouldn't matter because it disappears after it exits the scope. On subsequent calls to the reserve function, every thing repeats and there should only be one array in the heap which arr points to.
I do believe that my thinking is probably erroneous in some way.
#include "Vector.h"
namespace Vector {
vector::vector() {
sz = 0;
space = 0;
arr = nullptr;
}
vector::vector(int n) {
sz = n;
space = n;
arr = new int[n];
for(int i = 0; i < n; i++) {
arr[i] = 0;
}
}
void vector::push_back(int x) {
if(sz == 0) {
reserve(1);
} else if (sz == space) {
reserve(2*space);
}
arr[sz] = x;
sz++;
}
void vector::reserve(int n) {
if (n == 1) {
arr = new int[1]; //arr was a nullptr beforehand
}
int* temp = new int[n];
for(int i = 0; i < n; i++) {
temp[i] = arr[i];
}
delete[] arr;
arr = temp;
space = n;
}
Your code assumes in vector::reserve(int n) that arr is null.
Instead maybe spilt up how reserve functions based on whether or not arr is null.
void vector::reserve(int n) {
if (arr) { //handle case when arr is null
space += n;
arr = new int[space];
//no need to copy anything!
} else { //handle case when arr is not null
int* tmp(new int[space + n]);
for(int i = 0; i < space; i++) {
tmp[i] = arr[i];
}
delete[] arr;
arr = tmp;
space += n;
}
}
Also the above code assumes you mean to reserve space+n instead of allowing reserve to shrink the array as you'll lose data if you reserve less then a previous reserve. It's usually better practice to not use assumptions about a pointer's state when working with them because when your code gets more complex the assumptions can end up getting forgotten or more obscure.
I have same issues too. I have created two pointers that points in the same address in heap. When I'm trying too deallocate the memory, and the result is only one pointer that can do that, it's the first pointers that point that address. The second or third pointers that points that address doesn't have an authority to deallocate the memory, but only the first pointers who have that authority.
Example
int *a = new int[5];
int *b = a;
int *c = a;
Pointers b and c doesn't have an authority too dealloacte the memory address that pointers a pointed. Therefore, the memory wasn't deallocated if i'm saying delete[] b nor delete[] c, they didn't have an authority for doing that. Then I tried to write delete [] a and that worked. I don't have an real answers, and I just trying to approaching through my try and errors that I have done. And that's what I got.
Actually this case is violating the rules, but C++ still allowed us to do it, it's called undefined behaviors. We are violating the rules of delete[] operators by, but C++ still allowed you to do, and as the result, you get unexpected output.
Not too much wrong in there.
Bugs
if (n == 1) {
arr = new int[1]; //arr was a nullptr beforehand
}
The comment cannot be guaranteed. Nothing prevents multiple calls of resize including a call of reserve(1), and that will leak whatever memory was pointed at by arr. Instead consider
if (arr == nullptr) {
arr = new int[n]; //arr was a nullptr beforehand
}
now the comment is guaranteed to be true.
The copy loop overshoots the end of arr every time the size of the array is increased.
for(int i = 0; i < n; i++) {
temp[i] = arr[i];
}
arr is only good up to arr[sz-1]. If n is greater than space, and it almost always will be, arr[i] wanders into the great wilds of Undefined Behaviour. Not a good place to go.
for(int i = 0; i < n && i < sz; i++) {
temp[i] = arr[i];
}
Checks both n and sz to prevent overrun on either end and copying of data that has not been set yet. If there is nothing to be copied, all done.
Targets of opportunity
The class needs a destructor to release any memory that it owns (What is ownership of resources or pointers?) when it is destroyed. Without it, you have a leak.
vector::~vector() {
delete[] arr;
}
And if it has a destructor, the Rule of Three requires it to have special support functions to handle (at least) copying of the class or expressly forbid copying.
// exchanges one vector for the other. Generally useful, but also makes moves
// and assignments easy
void vector::swap(vector& a, vector& b)
{
std::swap(a.sz, b.sz);
std::swap(a.space, b.space);
std::swap(a.arr, b.arr);
}
// Copy constructor
vector::vector(const vector& src):
sz(src.sz),
space (src.space),
arr(new int[space])
{
for(int i = 0; i < sz; i++) {
arr[i] = src.arr[i];
}
}
// move constructor
vector::vector(vector&& src): vector()
{
swap(*this, src);
}
// assignment operator
vector::vector& vector::operator=(vector src)
{
swap(*this, src);
return *this;
}
The Copy Constructor uses a Member Initializer List. That's the funny : bit.
The assignment operator makes use of the Copy and Swap Idiom. This isn't the fastest way to implement the assignment operator, but it is probably the easiest. Start with easy and only go to hard if easiest doesn't meet the requirements.

How do I stop my resize function from causing _BLOCK_TYPE_IS_VALID(pHead -> nBlockUse)?

I've been tasked with implementing a stack using arrays However, when I run the program it says _BLOCK_TYPE_IS_VALID(pHead -> nBlockUse). The debugger directed me to the delete statement in the resize function, but I'm unsure how to fix the problem.
Note: I'm trying to do so without using vectors.
void resize(){
Type* temp = new Type[asz + 2]; // store old values
for (int i = 0; i < asz; ++i){ temp[i] = arr[i]; }
delete[asz] arr; // delete old array
arr = temp; // keep new larger arr
delete[] temp;
asz =+2; // array size
}
Here's a couple of changes that may fix your problem. You don't initialise sz, your final for-loop was copying according to the new increased size, yet tempwas only the old size. You also don't appear to set the new sz anywhere. Could be any or all of these that cause a memory overwrite invalidating the debug blocks and causing the assertion you have seen.
void resize(Type& arg){
Type* temp = new Type[arg.sz]; // store old values
for (int i = 0; i < arg.sz; ++i){ temp[i] = arg[i]; }
int oldSz = arg.sz, newSz=arg.sz + 2;
delete[] arg; // delete old array
arg = new Type[newSz]; // create new larger arr
arg.sz = newSz;
for (int i = 0; i < oldSz; ++i){ arg[i] = temp[i]; } //copy back
delete[] temp;
}

how to delete a char**

I am basically wondering how to delete a double pointer, for example char**. This is because I ran into an access violation problem which I don't quite understand. Here is the code:
StatsManager::_statsNameList = new char*[StatsManager::MAX_STATS_COUNT*StatsManager::MAX_CHANNEL_COUNT*StatsManager::MAX_ROI_COUNT];
if(NULL != StatsManager::_statsNameList )
{
for (int i = 0; i < StatsManager::MAX_CHANNEL_COUNT; i++ )
{
for (int j = 0; j < StatsManager::MAX_ROI_COUNT; j++ )
{
for (int k = 0; k < StatsManager::MAX_STATS_COUNT; k++ )
{
char* pList = StatsManager::_statsNameList[i*area + j*StatsManager::MAX_STATS_COUNT + k];
if (NULL != pList)
{
// following line is where the exception throws
delete[] StatsManager::_statsNameList[i*area + j*StatsManager::MAX_STATS_COUNT + k];
StatsManager::_statsNameList[i*area + j*StatsManager::MAX_STATS_COUNT + k] = NULL;
}
}
}
}
}
delete[] StatsManager::_statsNameList;
StatsManager::_statsNameList = NULL;
I am very confused because for the inner loop where the exception throws, I watched the pLsit is a bad pointer, so how come the if (NULL != pList) still get passed?
And what is the correct way to delete a char**? Thanks a lot.
Usually you have to follow two points:
If you used new[] for allocation use delete[] for deallocation, and if new was used for allocation delete has to be used to free the memory;
You have to free the memory on every level it was allocated, e.g.
int **pp = new *int;
*pp = new int;
**pp = 5;
delete *pp;
delete pp;
So, delete of the same type as new has to called the same number of times, but in reverse order.
You need to use the delete or delete[] operator that matches the operator used to allocate. So new[] is followed by delete[], and new by delete.
You cannot delete a char**, it's just a pointer to a pointer to a char. It depends on the object it's actually holding. Logically, a char** would itself contain an array like new char*[x], and is itself filled with objects allocated with new char[x]. In that case you need to loop over the array and delete[] those, then delete[] the outer array.

Copying content of array to resized array in C++

I've searched through many topics here, but they didn't seem to answer me exactly.
I'm trying to do some dynamic reallocation od arrays in C++. I can't use anything from STL libraries as I need to use this in homework where STL (vectors,...) is explicitly forbidden.
So far, I've tried to elaborate with code like this:
int * items = new int[3]; //my original array I'm about to resize
int * temp = new int[10];
for (int i = 0; i < 3; i++) temp[i] = items[i];
delete [] items; //is this necessary to delete?
items = new int [10];
for (int i = 0; i < 10; i++) items[i] = temp[i];
delete [] temp;
This seem to work, but what bothers me is the excessive number of iterations. Can't this be done anyhow smarter? Obviously, I'm working with much larger arrays than this. Unfortunately, I have to work with arrays though.
edit: When I try to do items = temp; instead of
for (int i = 0; i < 10; i++) items[i] = temp[i]; and try to std::cout all my elements, I end up with losing first two elements, but valgrind prints them correctly.
Yes, the first delete[] is necessary. Without it, you'd be leaking memory.
As to the code that comes after that first delete[], all of it can be replaced with:
items = temp;
This would make items point to the ten-element array you've just populated:
int * items = new int[3]; //my original array I'm about to resize
int * temp = new int[10];
for (int i = 0; i < 3; i++) temp[i] = items[i];
delete [] items; //delete the original array before overwriting the pointer
items = temp;
Finally, don't forget to delete[] items; when you are done with the array.
The containers of the STL were made to ease work like this. It is tedious, but there is not much of a choice, when you need to use C-arrays.
The deletion of
delete [] items;
is necessary, as when you abandon the reference to the array, which you would do with assigning a new reference in
items = new int [10];
will cause a memory leak, so this is necessary.