How to delete the last element from array with pointers in C++? - c++

I try to build a function which deletes the last element of an array. So I need an input array and its dimension, then delete the last term and obtain a new output array. I don't want that. My goal is to somehow make the output array the new input array. In other words, I want to overwrite the input array with the output array.
So if dimension is 4, I don't want to have a 4-dim array in the memory but only 3-dim table after the deletion.
void del (int* ptr_array, int dim) {
int* temp = ptr_array; //Hold the very first address of the input array.
ptr_array = new int[dim - 1]; // Let the address of the input array be
// the address of new output array. Overwritting.
for (int i = 0; i < dim - 1; i++) {
ptr_array = (temp+i); // Will it remember what is temp+1 if I have
// already overwritten the arrays?
ptr_array++;
}
//delete[] ptr_array; - this one is out of the questions - deletes now the input table.
}
Can you tell me what is wrong with this code? - in fact it doesn't change anything

in you function
for (int i = 0; i < dim - 1; i++) {
ptr_array = (temp+i); // Will it remember what is temp+1 if I have
// already overwritten the arrays?
ptr_array++;
}
does nothing, you wanted
for (int i = 0; i < dim - 1; i++) {
ptr_array[i] = temp[i];
}
Note the delete in your comment is invalid because you do not delete the result of a new[] but a pointer inside the allocated array
If the call is like
int * v = ...;
del(v);
// here v is unchanged
probably you wanted to modify v, in that case you can return the new array or to use an input-output variable using a reference
First possibility :
int* del (int* ptr_array, int dim) {
int* new_array = new int[dim - 1];
for (int i = 0; i < dim - 1; i++) {
new_array[i] = ptr_array[i];
}
delete[] ptr_array;
return new_array;
}
with
int * v = ...;
v = del(v);
Second possibility
void del (int*& ptr_array, int dim) {
int* new_array = new int[dim - 1];
for (int i = 0; i < dim - 1; i++) {
new_array[i] = ptr_array[i];
}
delete[] ptr_array;
ptr_array = new_array;
}
with
int * v = ...;
del(v);
// here v is the new array
Warning these codes suppose the input array has at least one element
However the use of an std::vector<int> does all of that for you and is more practical to use
std::vector<int> v;
...
v.resize(v.size() - 1);
or
std::vector<int> v;
...
v.pop_back();

Related

C++ concatenate two arrays without deep copying

I have two arrays of each size 3 as:
void main() {
double* arr1 = new double[3];
double* arr2 = new double[3];
for(int i = 0; i < 3; i++) {
arr1[i] = 0;
arr2[i] = 0;
}
}
And I have a function that takes a double array as pointer:
void func(double* arr_6D) {
// expected arr size = 6.
// manipulates values of arr
for(int i = 0; i < 6; i++) {
arr_6D[i] = 1;
}
}
I want to pass in arr1 and arr2 together to the function so that their original values are manipulated by the function.
How can I do this?
Below wouldn't work since it's making a copy of the original arrays:
double *arr_merged = new double[6];
arr_merged[0] = arr1[0];
arr_merged[1] = arr1[1];
arr_merged[2] = arr1[2];
arr_merged[3] = arr2[0];
arr_merged[4] = arr2[1];
arr_merged[5] = arr2[2];
func(arr_merged);
you cannot modify the size of an array you create using new double[<size>], to be able to do your merge so to modify the size use std::vector<float>, also offering a lot of additional behaviors
'func(double * arr_6D) is from a library and fixed. I can't change it to for example, func(std::vector &arr_6d)
you can get the underlying array serving as element storage using the operation data()
std::vector<double> arr1 = { ... }
...
std::vector<double> arr2 = { ... }
...
// concatenate arr1 with arr2
arr1.insert( arr1.end(), arr2.begin(), arr2.end() );
...
// call your func with underlying array
func(arr1.data());
warning to take care when manipulating the underlying array

Is this extra step necessary when freeing dynamically allocated memory

During the expansion of a dynamically allocated array, I find myself writing this :
void HPQueue::expandCapacity() {
char **prevArray = array;
capacity *= 2;
array = new char*[static_cast<size_t>(capacity)];
for (int i = 0; i < capacity; i++) {
array[i] = new char;
}
for (size_t i = 0; i < count; i++) {
array[i] = prevArray[i];
LINE XX: delete prevArray[i]; <----------- This line seems to be the problem, Since it also deletes array[i]
}
delete[] prevArray;
}
But this line is necessary if initially the constructor looks something like this:
HPQueue::HPQueue::() {
capacity = INITIAL_CAPACITY;
array = new char*[static_cast<size_t>(logSize)];
for (int i = 0; i < logSize; i++) {
array[i] = new char;
}
count = 0;
}
Note :
/* instances variables */
char **array;
size_t count;
Is this LINE XX: not necessary ?
No, you shouldn't be calling new char for the first count elements of array. You should be copying from the first count elements of prevArray.
You don't need to call new char at all. If you use nullptr instead, you can still safely delete[] array[i] when you remove an element.
But you shouldn't be doing this. In order of preference:
Use std::vector<std::string> array, it does all this for you.
Use std::unique_ptr<std::unique_ptr<char[]>[]> array; std::size_t capacity; and reassign with array = std::make_unique<std::unique_ptr<char[]>[]>(capacity); and move with std::move(prevArray.get(), prevArray.get() + count, array.get());
Use char **array; std::size_t capacity;, reassign with array = new char*[capacity]; and move with std::copy_n(prevArray, count, array);
So if you are required to go with the last one, you get
HPQueue::HPQueue()
: capacity(INITIAL_CAPACITY),
array(new char*[INITIAL_CAPACITY]),
count(0)
{
std::fill_n(array, capacity, nullptr);
}
void HPQueue::expandCapacity() {
char **prevArray = array;
capacity *= 2;
array = new char*[capacity];
auto pos = std::copy_n(prevArray, count, array);
std::fill_n(pos, capacity - count, nullptr);
delete[] prevArray;
}

Deallocating memory of this particular 2d array

I'm currently using a particular API such that I must use raw pointers, however given the particular arrangement of the pointers I'm not sure how to best go about clearing the memory and avoiding any undefined behaviour in doing so.
double *data1 = new double[rows*columns];
double **data2 = new double*[rows];
data2[0] = data1; // Point to first row
for (int i = 1; i < columns; i++) {
data2[i] = data2[i - 1] + rows;
}
I've attempted something like below, but I don't think it's right.
for(int i = 0; i < rows; i++) {
delete [] data2[i];
}
delete [] data2;
delete [] data1;
Who owns What?
Is the question which will dictate how you delete objects.
What I think you're doing is creating one large array to hold a two-dimensional array of data, and then creating another array to hold pointers to the beginning of each row.
So that's two news and therefore two deletes.
It might be easier to visualise like this:
struct matrix_view
{
int rows, columns;
// this pointer owns a block of doubles
double* entire_buffer = nullptr;
// this pointer owns a block of pointers, but not the memory
// they point to
double** row_pointers = nullptr;
};
matrix_view create_matrix(int rows, int columns)
{
auto result = matrix_view{ rows, columns, nullptr, nullptr };
auto size = rows * columns;
result.entire_buffer = new double [size];
result.row_pointers = new double* [rows];
auto first = result.entire_buffer;
auto last = first + size;
auto dest = result.row_pointers;
while (first != last) {
*dest++ = first;
first += columns;
}
return result;
}
void destroy_matrix(matrix_view m)
{
// always destroy in reverse order
delete [] m.row_pointers;
delete [] m.entire_buffer;
}

C++ pointer to int in loops?

Ok, so I'm quite new to C++ and I'm sure this question is already answered somewhere, and also is quite simple, but I can't seem to find the answer....
I have a custom array class, which I am using just as an exercise to try and get the hang of how things work which is defined as follows:
Header:
class Array {
private:
// Private variables
unsigned int mCapacity;
unsigned int mLength;
void **mData;
public:
// Public constructor/destructor
Array(unsigned int initialCapacity = 10);
// Public methods
void addObject(void *obj);
void removeObject(void *obj);
void *objectAtIndex(unsigned int index);
void *operator[](unsigned int index);
int indexOfObject(void *obj);
unsigned int getSize();
};
}
Implementation:
GG::Array::Array(unsigned int initialCapacity) : mCapacity(initialCapacity) {
// Allocate a buffer that is the required size
mData = new void*[initialCapacity];
// Set the length to 0
mLength = 0;
}
void GG::Array::addObject(void *obj) {
// Check if there is space for the new object on the end of the array
if (mLength == mCapacity) {
// There is not enough space so create a large array
unsigned int newCapacity = mCapacity + 10;
void **newArray = new void*[newCapacity];
mCapacity = newCapacity;
// Copy over the data from the old array
for (unsigned int i = 0; i < mLength; i++) {
newArray[i] = mData[i];
}
// Delete the old array
delete[] mData;
// Set the new array as mData
mData = newArray;
}
// Now insert the object at the end of the array
mData[mLength] = obj;
mLength++;
}
void GG::Array::removeObject(void *obj) {
// Attempt to find the object in the array
int index = this->indexOfObject(obj);
if (index >= 0) {
// Remove the object
mData[index] = nullptr;
// Move any object after it down in the array
for (unsigned int i = index + 1; i < mLength; i++) {
mData[i - 1] = mData[i];
}
// Decrement the length of the array
mLength--;
}
}
void *GG::Array::objectAtIndex(unsigned int index) {
if (index < mLength) return mData[index];
return nullptr;
}
void *GG::Array::operator[](unsigned int index) {
return this->objectAtIndex(index);
}
int GG::Array::indexOfObject(void *obj) {
// Iterate through the array and try to find the object
for (int i = 0; i < mLength; i++) {
if (mData[i] == obj) return i;
}
return -1;
}
unsigned int GG::Array::getSize() {
return mLength;
}
I'm trying to create an array of pointers to integers, a simplified version of this is as follows:
Array array = Array();
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject(&j);
}
Now the problem is that the same pointer is used for j in every iteration. So after the loop:
array[0] == array[1] == array[2];
I'm sure that this is expected behaviour, but it isn't quite what I want to happen, I want an array of different pointers to different ints. If anyone could point me in the right direction here it would be greatly appreciated! :) (I'm clearly misunderstanding how to use pointers!)
P.s. Thanks everyone for your responses. I have accepted the one that solved the problem that I was having!
I'm guessing you mean:
array[i] = &j;
In which case you're storing a pointer to a temporary. On each loop repitition j is allocated in the stack address on the stack, so &j yeilds the same value. Even if you were getting back different addresses your code would cause problems down the line as you're storing a pointer to a temporary.
Also, why use a void* array. If you actually just want 3 unique integers then just do:
std::vector<int> array(3);
It's much more C++'esque and removes all manner of bugs.
First of all this does not allocate an array of pointers to int
void *array = new void*[2];
It allocates an array of pointers to void.
You may not dereference a pointer to void as type void is incomplete type, It has an empty set of values. So this code is invalid
array[i] = *j;
And moreover instead of *j shall be &j Though in this case pointers have invalid values because would point memory that was destroyed because j is a local variable.
The loop is also wrong. Instead of
for (int i = 0; i < 3; i++) {
there should be
for (int i = 0; i < 2; i++) {
What you want is the following
int **array = new int *[2];
for ( int i = 0; i < 2; i++ )
{
int j = i + 1;
array[i] = new int( j );
}
And you can output objects it points to
for ( int i = 0; i < 2; i++ )
{
std::cout << *array[i] << std::endl;
}
To delete the pointers you can use the following code snippet
for ( int i = 0; i < 2; i++ )
{
delete array[i];
}
delete []array;
EDIT: As you changed your original post then I also will append in turn my post.
Instead of
Array array = Array();
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject(&j);
}
there should be
Array array;
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject( new int( j ) );
}
Take into account that either you should define copy/move constructors and assignment operators or define them as deleted.
There are lots of problems with this code.
The declaration void* array = new void*[2] creates an array of 2 pointers-to-pointer-to-void, indexed 0 and 1. You then try to write into elements 0, 1 and 2. This is undefined behaviour
You almost certainly don't want a void pointer to an array of pointer-to-pointer-to-void. If you really want an array of pointer-to-integer, then you want int** array = new int*[2];. Or probably just int *array[2]; unless you really need the array on the heap.
j is the probably in the same place each time through the loop - it will likely be allocated in the same place on the stack - so &j is the same address each time. In any case, j will go out of scope when the loop's finished, and the address(es) will be invalid.
What are you actually trying to do? There may well be a better way.
if you simply do
int *array[10];
your array variable can decay to a pointer to the first element of the list, you can reference the i-th integer pointer just by doing:
int *myPtr = *(array + i);
which is in fact just another way to write the more common form:
int *myPtr = array[i];
void* is not the same as int*. void* represent a void pointer which is a pointer to a specific memory area without any additional interpretation or assuption about the data you are referencing to
There are some problems:
1) void *array = new void*[2]; is wrong because you want an array of pointers: void *array[2];
2)for (int i = 0; i < 3; i++) { : is wrong because your array is from 0 to 1;
3)int j = i + 1; array[i] = *j; j is an automatic variable, and the content is destroyed at each iteration. This is why you got always the same address. And also, to take the address of a variable you need to use &

How to resize a dynamically allocated array of polymorphic objects?

I have a dynamically allocated array of polymorphic objects that I would like to resize without using STL library (vectors, etc). I've tried moving the original to a temporary array, then deleting the original, then setting the original equal to the temporary, like this:
int x = 100;
int y = 150;
Animal **orig = new Animal*[x];
Animal **temp = new Animal*[y];
//allocate orig array
for(int n = 0; n < x; n++)
{
orig[n] = new Cat();
}
//save to temp
for(int n = 0; n < x; n++)
{
temp[n] = orig[n];
}
//delete orig array
for(int n = 0; n < x; n++)
{
delete orig[n];
}
delete[] orig;
//store temp into orig
orig = temp;
However, when I try to access the element for example:
cout << orig[0]->getName();
I get a bad memeory alloc error:
Unhandled exception at at 0x768F4B32 in file.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x0033E598.
//delete orig array
for(int n = 0; n < x; n++)
{
delete orig[n];
}
For this particular case, don't do this. You are actually deleting the objects not the array. So all the objects in the temp array are pointing to invalid locations. Simply do delete [] orig to deallocate the original array.
You are copying wrong. Instead of copying your temp array is simply pointing to the same location as that of the orig. Now when you delete the orig the temp pointers point to an invalid location.
//save to temp
for(int n = 0; n < x; n++)
{
//temp[n] = orig[n];
// Try this instead
strcpy(temp[n], orig[n]);
}