I tried to write a function that gets an object ("Stone") and deletes the stone from a given array. code:
void Pile::del_stone(Stone &s)
{
Stone *temp = new Stone[size - 1];//allocate new array
for (int i = 0;i <size;++i)
{
if (s != Pile_arr[i])//if the given object to delete is different from the current
{
temp[i] = Pile_arr[i];//copy to the new array
}
else
{
i--;
}
}
Pile_arr = temp;
set_size(this->size - 1);
temp = NULL;
delete[] temp;
}
Pile_arr is a member of Pile class.
The problem is that i get an infinite loop, because i decrease i. I cant figure out how to solve this issue. Any ideas?
Use two indexes: i and j. Use i to know which element of the original array you are looking and j to know where to put the element in temp.
You need to use a separate counter to track where new elements should be placed.
I have used n below:
Stone *temp = new Stone[size - 1];
int n = 0; // Stores the current size of temp array
for (int i = 0;i <size;++i) {
if (s != Pile_arr[i]) {
temp[n++] = Pile_arr[i];
}
}
It's also worth considering the case where s is not found in the array, as this would cause a runtime error (Attempting to add size elements to an array of size size - 1).
Using a STL container would be a far better option here.
This function will:
Allocate a new array of length size-1
Search for the intended object
If you find it, copy it to the same exact position in the array
If you don't --i
Finally, ++i
First of all, this function is bad for 3 reasons:
It only copies one item over--the given item. You have an array with only 1 object.
It copies the item from index to index. Since the final array is one smaller, if the object is at the max original index, it will be out of bounds for the new array.
If the object is not immediately found, the array will get stuck, as you decrease the index, and then increase it using the loop--you'll never move again.
Stone *temp = new Stone[size - 1];//allocate new array
for (int i = 0;i
Instead:
Cache the found object, then delete it from the original array or mark it. temp = found object
Copy the array, one by one, without copying empty spaces and closing the gap. Copy temp_array[i] and increment i if and only if temp_array[j] is not marked/deleted. Increment j
Decide where to put the found object.
Once again, you can decide to use separate indexes--one for parsing the original array, and one for filling the new array.
Related
I'm writing my own array sorting method and I have created a duplicate array to stored the objects as they are stored. The arrays are both arrays of pointers and so I need to delete my temporary array without deleting the items it points to. In the code snippet below I am leaking memory as I either delete all the items or do not delete anything.
//In constructor initialiser list
m_listArray( new PathFindingTile*[maxSize] )
void sort()
{
auto** sorted = new PathFindingTile*[m_size];
sorted[0] = m_listArray[0];
for (int i = 1; i < m_size; i++)
{
sorted[i] = m_listArray[i];
for (int j = i; j - 1 >= 0; j--)
{
if (*m_listArray[j] < *m_listArray[j - 1])
{
PathFindingTile* temp = sorted[j - 1];
sorted[j - 1] = m_listArray[i];
sorted[j] = temp;
}
else
{
sorted[i] = m_listArray[i];
break;
}
}
}
m_listArray = sorted;
//Both 'delete sorted' and 'delete[] sorted' delete the contents of sorted, but I'd only like to delete the array pointer
delete sorted;
}
How can I transfer the duplicated list back to the original list without leaking memory?
m_listArray = sorted;
On this line, you leak the array that m_listArray was pointing at before the assignment.
You must delete the array before (the only) pointer to it is overwritten. Also, delete is wrong for deleting pointers from new[]. delete[] is correct:
delete[] m_listArray;
m_listArray = sorted;
P.S. It is not a good idea to have bare pointers to owned memory. I recommend using std::vector instead. Also, it should not be necessary to allocate a new array in order to sort one. You could simply swap elements within the array.
I think you just remove pointer to the first element in the array. I believe you need to release the array with the follow command.
delete[] sorted
Read more about delete and delete[] [delete vs delete[]]1
This question already has answers here:
Using sizeof with a dynamically allocated array
(5 answers)
Closed 8 years ago.
This is for a non-graded challenge problem where I am looking to find as many prime numbers as fast as possible. One of the constraints is that I must use new/delete, so std::vector is not an option. In this problem, I need to add to an array (in my case a dynamically created array named list) that holds the primes. My goal is to achieve similar functionality to vector, where new memory only needs to be allocated if there isn't enough room in the current array, and when the current array fills up a new array with 2 times the length is allocated. My function to add a prime to the list is below
void PrimeList::addPrimeToList(int newPrime) {
if( sizeof(list)/sizeof(int) > total ) { // there is still room in the array
list[total++] = newPrime;
} else { // list has run out of space to put values into
int *newList = new int [total*2]; // new list to hold all previous primes and new prime
for(int i=0; i < total; i++) { // for every old prime
newList[i] = list[i]; // add that old prime to the new list
}
newList[total++] = newPrime; // set largest and the last index of the new list to the new prime
delete [] list; // get rid of the old list
list = newList; // point the private data member list to the newly created list.
}
}
Note: total is a private data member that holds the amount of primes found up to this point.
My issue is that the else statement (and the time consuming allocation/deallocation) is happening every single time the function is called (with the exception that the very first two calls always run the first part of the if). I would think that the if part would run the vast majority of the time - whenever the list still has space - so why isn't it?
The reason this happens is that the expression that you use for the array size, i.e.
sizeof(list)/sizeof(int)
is a constant expression. Its value is not dependent on the allocated array pointed to by the list pointer.
You need to store the allocated size separately to make this code work:
if( allocatedSize > total ) { // there is still room in the array
list[total++] = newPrime;
} else { // list has run out of space to put values into
int *newList = new int [total*2]; // new list to hold all previous primes and new prime
allocatedSize *= 2;
for(int i=0; i < total; i++) { // for every old prime
newList[i] = list[i]; // add that old prime to the new list
}
newList[total++] = newPrime; // set largest and the last index of the new list to the new prime
delete [] list; // get rid of the old list
list = newList; // point the private data member list to the newly created list.
}
I am trying to insert data into a leaf node (an array) of a B-Tree. Here is the code I have so far:
void LeafNode::insertCorrectPosLeaf(int num)
{
for (int pos=count; pos>=0; pos--) // goes through values in leaf node
{
if (num < values[pos-1]) // if inserting num < previous value in leaf node
{continue;} // conitnue searching for correct place
else // if inserting num >= previous value in leaf node
{
values[pos] = num; // inserts in position
break;
}
}
count++;
} // insertCorrectPos()
Before the line values[pos] = num, I think need to write some code that shifts the existing data instead of overwriting it. I am trying to use memmove but have a question about it. Its third parameter is the number of bytes to copy. If I am moving a single int on a 64 bit machine, does this mean I would put a "4" here? If I am going about this completely wrong any any help would be greatly appreciated. Thanks
The easiest way (and probably the most efficient) would be to use one of the standard libraries predefined structures to implement "values". I suggest either list or vector. This is because both list and vector has an insert function that does it for you. I suggest the vector class specifically is because it has the same kind of interface that an array has. However, if you want to optimize for speed of this action specifically, then I would suggest the list class because of the way it is implemented.
If you would rather to it the hard way, then here goes...
First, you need to make sure that you have the space to work in. You can either allocate dynamically:
int *values = new int[size];
or statically
int values[MAX_SIZE];
If you allocate statically, then you need to make sure that MAX_SIZE is some gigantic value that you will never ever exceed. Furthermore, you need to check the actual size of the array against the amount of allocated space every time you add an element.
if (size < MAX_SIZE-1)
{
// add an element
size++;
}
If you allocate dynamically, then you need to reallocate the whole array every time you add an element.
int *temp = new int[size+1];
for (int i = 0; i < size; i++)
temp[i] = values[i];
delete [] values;
values = temp;
temp = NULL;
// add the element
size++;
When you insert a new value, you need to shift every value over.
int temp = 0;
for (i = 0; i < size+1; i++)
{
if (values[i] > num || i == size)
{
temp = values[i];
values[i] = num;
num = temp;
}
}
Keep in mind that this is not at all optimized. A truly magical implementation would combine the two allocation strategies by dynamically allocating more space than you need, then growing the array by blocks when you run out of space. This is exactly what the vector implementation does.
The list implementation uses a linked list which has O(1) time for inserting a value because of it's structure. However, it is much less space inefficient and has O(n) time for accessing an element at location n.
Also, this code was written on the fly... be careful when using it. There might be a weird edge case that I am missing in the last code segment.
Cheers!
Ned
I have this code for managing dynamic collection List, which is mostly inspired with .NET System.List collection, but this is written in normal C++.
void List<T>::Insert(int index, T item)
{
if(index > GetLength() && index >= 0)
throw new StandartException("Index was out of array range");
if(GetLength()==length)
{
T * newl = new T[length + 4];
this->CopyTo(newl);
delete[] this->items;
this->items = newl;
length += 4;
}
T * store = new T[length];
CopyTo(store, index);
store[index] = item;
CopyTo((store + index + 1), index, GetLength() - index);
used++;
delete[] items;
items = store;
}
template <typename T>
void List<T>::CopyTo(T * destination, int start, int count)
{
for(int i = start, c = 0;i < GetLength() && c < count;i++, c++)
*(destination + i) = items[i];
}
So there is method Insert, which has to insert item on specified index in array.
For first, I'm checking if is index specified between 0 and Length + 1 (because I need to have a option to add item on the ond of collection). Then I'm testing if it is not end of allocated array (GetLength() = gets number of elements in array, length = number of allocated space for elements). If it is, I'm allocating new space for array, copying actual elements, freeing old storage and setting pointer to new address.
After that I'm allocating new space again. I'm copying actual elements from zero to index - 1, setting item which has to be inserted on it's position and copying other old elements to thier indexes (their previous index + 1). On the end I'm freeing old space and adding new.
ERROR: I started debugging. Everything was normal, I've run Insert for first without problem, but on first deletion (delete[] this->items; in if block) I've received this error:
Does anybody know why am I getting this and how can I repair it? I think that I haven't gone throught array range anywhere.
Please help.
Your problem is this line:
T * store = new T[length];
You insert an item, but don't allocate an array that is any larger than before. When you go to CopyTo the new array, you overflow the array.
I need some assistance with a C++ project. What I have to do is remove the given element from an array of pointers. The technique taught to me is to create a new array with one less element and copy everything from the old array into the new one except for the specified element. After that I have to point the old array towards the new one.
Here's some code of what I have already:
I'm working with custom structs by the way...
Data **values = null; // values is initialized in my insert function so it is
// populated
int count; // this keeps track of values' length
bool remove(Data * x) {
Data **newArray = new Data *[count - 1];
for (int i = 0; i < count; i++) {
while (x != values[i]) {
newArray[i] = values[i];
}
count -= 1;
return true;
}
values = newArray;
return false;
}
So far the insert function works and outputs the populated array, but when I run remove all it does is make the array smaller, but doesn't remove the desired element. I'm using the 0th element every time as a control.
This is the output I've been getting:
count=3 values=[5,6,7] // initial insertion of 5, 6, 7
five is a member of collection? 0
count=3 values=[5,6] // removal of 0th element aka 5, but doesn't work
five is a member of collection? 0
count=4 values=[5,6,5] // re-insertion of 0th element (which is stored in
five is a member of collection? 0 // my v0 variable)
Could anyone nudge me in the right direction towards completing this?
First of all, your code is leaking memory like no good! Next you only copy the first element and not even that if the first element happens to be the one you want to remove. Also, when you return from your function, you haven't changed your internal state at all. You definitely want to do something along the lines of
Data** it = std::find(values, values + count, x);
if (it != values + count) {
std::copy(it + 1, values + count, it);
--count;
return true;
}
return false;
That said, if anybody taught you to implement something like std::vector<T> involving reallocations on every operation, it is time to change schools! Memory allocations are relatively expensive and you want to avoid them. That is, when implementing something like a std::vector<T> you, indeed, want to implement it like a std::vector<T>! That is you keep an internal buffer of potentially more element than there are and remember how many elements you are using. When inserting a new element, you only allocate a new array if there is no space in the current array (not doing so would easily result in quadratic complexity even when always adding elements at the end). When removing an element, you just move all the trailing objects one up and remember that there is one less object in the array.
Try this:
bool remove(Data * x)
{
bool found = false;
// See if x is in the array.
for (int i = 0; i < count; i++) {
if (x != values[i]) {
found = true;
break;
}
}
if (!found)
{
return false;
}
// Only need to create the array if the item to be removed is present
Data **newArray = new Data *[count - 1];
// Copy the content to the new array
int newIndex = 0;
for (int i = 0; i < count; i++)
{
if (x != values[i])
newArray[newIndex++] = values[i];
}
// Now change the pointers.
delete[] values;
count--;
values = newArray;
return true;
}
Note that there's an underlying assumption that if x is present in the array then it's there only once! The code will not work for multiple occurrences, that's left to you, seeing as how this is a school exercise.