2D array of pointers: Deleting the array but not the pointers? - c++

In my code, I have a 2D array of pointers to my data:
Data***
The reason I'm not using array notation is because the size is not determined at compile time.
So, somewhere in my code I allocate all the necessary space:
arr = new Data **[xVals];
for (int i = 0; i < xVals; i++)
{
arr[i] = new Data *[yVals];
for (int j = 0; j < yVals; j++)
{
arr[i][j] = nullptr;
}
}
And then fill the array with my proper pointers some time later on.
Furthermore, the pointer also gets stored in a std::vector:
for(...) {
for(...) {
// Conditional statement; not the whole array gets filled, some parts stay nullptr
...
arr[xCoord][yCoord] = new Data(...);
myVector.push_back(arr[xCoord][yCoord]);
}
}
... // Do some other stuff that takes advantage of the spatial properties of the 2D array
Once I'm done using the 2D array, I want to delete it, but NOT delete the Data-pointers themselves, since they are now stored in my vector.
I've been trying the following:
for (int i = 0; i < xVals; i++)
{
// Delete all "column" arrays
delete[] arr[i];
}
// Delete
delete[] arr;
However, I get a corrupted heap error CRT detected that the application wrote to memory after end of heap buffer, so I'm not sure what exactly I did wrong there. How do I delete a 2D array without deleting the data it held?

Related

delete element inside pointers array (resize)

Im trying to understand pointers, below my code:
int main()
{
int size = 5; //Size of array
int position = 2; //Position to delete
int *pointer = new int[size]; //Pointer declaration
//Populates array with numbers starting at 1 up to size elements (5 in this case)
for (int i = 0 ; i < size; i++)
{
pointer[i] = i+1;
}
//Prints existing elements (numbers 1 to 5 in this case)
for (int i = 0 ; i < size; i++)
{
std::cout << pointer[i] << ", ";
}
return 0;
}
I know that if I do delete [] pointers; it will delete the array from the memory, but how can I delete just the object inside position 2 or resize the array?
You can't do either of those things. You can move items around within your existing allocation, and you can make a new allocation, copy items over, and delete the old allocation.
To work with data you should use a container called vector which provides member functions to remove an element or resize. A vector is the equivalent in C++ of what most other languages call an "array".

Pointer/Refer to an array?

Okay, I'm writing a program that will perform different functions on an array. If necessary, the array will need to change capacity. The instructions are:
Create an new array.
Copy the contents from the old array to the new.
Delete the old array.
This part is understand, but what I don´t understand is how to keep a reference to the array that the functions will work with. This is my code for creating a new array and move over the elements.
int newSize = m_size*2;
double *tempArray= new double[newSize];
for(int i=0; i<m_size-1; i++)
{
tempArray[i] = arr[i];
}
delete []arr;
for(int i=0; i<m_size-1; i++)
{
arr[i] = tempArray[i];
}
delete []tempArray;
}
All the other methods use arr so I would like to reference back to that. A pointer won´t work since it only points to the first element. How can I use my arr variable to refer to an array?
In C and C++ dynamic arrays are usually represented by a pointer to the first element and the number of elements. So I'm assuming the following declarations:
double *arr;
int m_size;
If by any chance you have arr decleared as a real array double arr[..], then you cannot do delete []arr nor change its size!
Then your code should be along the lines of:
int newSize = 2*m_size;
double *tempArray= new double[newSize];
for(int i=0; i<m_size-1; i++)
{
tempArray[i] = arr[i];
}
delete []arr;
arr = tempArray;
m_size = newSize;
But now I wonder: why m_size-1 in the loop?
And also, you can just do:
memcpy(tempArray, arr, sizeof(*arr) * m_size)); //or m_size-1?
All this is nice if it is an exercise. For real code it almost always better to use std::vector<double> and the resize() member function.
You got undefined behaviour in your code.
delete []arr;
for(int i=0; i<m_size-1; i++)
{
arr[i] = tempArray[i];
}
You delete the memory arr was pointing to and then assign to the deleted memory inside the loop. Instead you should just write:
delete []arr;
arr = tempArray;
The whole code would be:
int newSize = m_size*2;
double *tempArray= new double[newSize];
for(int i=0; i<m_size-1; i++) // -1 might be wrong, look below for a comment on this line.
{
tempArray[i] = arr[i];
}
delete []arr;
arr = tempArray;
m_size = newSize // stolen from the others *cough* since I oversaw the need.
// note that I don't call delete on tempArray.
}
Also I don't know how you allocated your first array but if you made it calling new double[m_size] then you'd want to delete the -1 in the loop condition of the for loop since you're checking for i < m_size and not i <= m_size.
You need to allocate memory for ar after deallocating it.
int newSize = m_size*2;
double *tempArray= new double[newSize];
for(int i=0; i<m_size-1; i++)
{
tempArray[i] = arr[i];
}
delete []arr;
ar = new double[newSize];
for(int i=0; i<m_size-1; i++)
{
arr[i] = tempArray[i];
}
delete []tempArray;
delete []arr;
for(int i=0; i<m_size-1; i++)
{
arr[i] = tempArray[i];
}
Oops. Don't access after delete. And don't delete unless it was allocated with new.
You simply can't reallocate an array declared as
int arr[100]
or similar.
Based on the code you've given, what you're currently performing is:
Create a new array (tempArray)
Copy the contents of the old (arr) array to the new (temp) - (note - what happens if you make the new array smaller than the old?)
Delete the old array
Copy the new values back into the deleted remains of the old array (note - you deleted arr so you can't use it now!)
Delete the new array (so everything is gone)
Basically, you need to fix step 2, to handle sizes, and get rid of steps 4 and 5 entirely - you just need to re-assign arr instead:
arr = tempArray
You just have to declare the array arr and put the values in it. You can refer to the array through its pointer arr or each element with arr[element_id].
You have a couple of options here:
Take the C-style approach of just storing the pointer to the first element like you have, plus the length. From those two you can calculate anything you need.
Use std::vector. It holds an array, allows you to easily resize it with functions like emplace_back, and can tell you its length with the size function.
The second approach is certainly preferred. If you're in C++, you should usually be using std::vector instead of raw arrays, unless you're looking for a fixed-sized one. In that case use std::array.
You also get the added benefit of copying a vector being as simple as vector1 = vector2;.

Deleteing 2D array correctly?

My question arises from this answer.
In the comments he mentions that I should delete the allocated dynamic 2D array in the reverse order.
However I did not understand much why this should be done. Here is the code:
//intialising array
int size = 10000;
double **array = new double[size];
for(int i = 0; i < size; i++)
array[i] = new double[size];
//conventional de-initialise
for(int i = 0; i < size; i++)
delete[] array[i];
delete[] array;
//reverse de-initialise
for(int i = size - 1; size >= 0; i--)//notice reverse order here
delete[] array[i];
delete[] array;
So my question is, is there any significant difference between the 2 methods of de-allocating a 2D array?
In your example there's no difference - you create 100K pointers, and then allocate memory for each. It doesn't matter how you allocate/deallocate memory and assign it to pointers array.
However your question is about why reverse deallocation was in another post, and opposite to your example it matters - counter variable is reused to countdown from last allocated object down to 0, when new memory allocation failed. If deallocating other direction you'd need additional variable there:
try
{
array = new double*[size];
// Don't shadow counter here.
for(counter = 0; counter < size; counter++)
{
array[counter] = new double[size];
}
}
catch(std::bad_alloc)
{
// delete in reverse order to mimic other containers.
for(--counter; counter >= 0;--counter)
{
delete[] array[counter];
}
delete[] array;

dynamically allocating atwo dimensional array where each row contains variable number of elements & freeing it in c++

How can I dynamically allocate a two dimensional array where each row contains variable element? How can I free this memory?
Actually you probably want a vector of vectors, something like this:
std::vector<std::vector<int> > vector_2d;
This way you'll benefit from the automatic memory management of the vector rather than having to manually manage the memory of an array of pointers to arrays of data.
You would need need to use pointers:
int ** a;
a = new (int*)[5];
for(int i = 0; i<5; i++)
{
a[i] = new int[x]; //where x is the size of this row
}
Something like this should work, but I didn't test it.
Just for the sake of completeness:
int ** a;
a = new (int*)[5];
for(int i = 0; i<5; i++)
{
a[i] = new int[x]; //where x is the size of this row
}
for(int i = 0; i<5; i++)
{
delete[] a[i];
}
detete[] a;

Expanding a dynamically allocated array

I have allocated an array as follows.
#include <iostream>
int main() {
const int first_dim = 3;
const int second_dim = 2;
// Allocate array and populate with dummy data
int** myArray = new int*[first_dim];
for (int i = 0; i < first_dim; i++) {
myArray[i] = new int[second_dim];
for (int j = 0; j < second_dim; j++) {
myArray[i][j] = i*second_dim + j;
std::cout << "[i = " << i << ", j = " << j << "] Value: " << myArray[i][j] << "\n";
}
}
// De-allocate array
for (int i = 0; i < first_dim; i++)
delete[] myArray[i];
delete[] myArray;
}
Let's say I want to add a 4th element to the first dimension, i.e. myArray[3]. Is this possible?
I've heard that Vectors are so much more efficient for this purpose, but I hardly know what they are and I've never used them before.
Yes, but in a very painful way. What you have to do is allocate new memory which now has your new desired dimensions, in this case 4 and 2, then copy all the contents of your matrix to your new matrix, and then free the memory of the previous matrix... that's painful. Now let's see how the same is done with vectors:
#include <vector>
using std::vector;
int main()
{
vector< vector <int> > matrix;
matrix.resize(3);
for(int i = 0; i < 3; ++i)
matrix[i].resize(2);
matrix[0][1] = 4;
//...
//now you want to make the first dimension 4? Piece of cake
matrix.resize(4);
matrix[3].resize(2);
}
HTH
edit:
some comments on your original code:
In C++ ALL_CAP_NAMES usually refer to macros (something you #define). Avoid using them in other contexts
why do you declare FIRSTDIM and SECONDDIM static? That is absolutely unnecessary. If a local variable is static it means informally that it will be the same variable next time you call the function with kept value. Since you technically can't call main a second sime this is useless. Even if you could do that it would still be useless.
you should wrire delete [] array[i]; and delete [] array; so the compiler knows that the int* and int** you're trying to delete actually point to an array, not just an int or int* respectively.
Let's say I want to add a 4th element to the first dimension, i.e. myArray[3]. Is this possible?
Yes, but it's a pain in the neck. It basically boils down to allocating a new array, just as your existing code does (hint: put it in the function and make the sizes arguments to that function) and copying compatible elements over.
Edit: One of the things that std::vector does for you is properly de-allocating you memory. In the code you have, failure to allocate one of the arrays along the 2nd dimension will result in a memory leak. A more robust solution would initialize pointers to 0 before performing any allocation. An exception block could then catch the exception and free whatever was partially allocated.
Because this code becomes complex quickly, people resort to allocating a single buffer and addressing using a stride or using a 1D array of 1D arrrays (i.e. std::vector of std::vectors).