Access violation when "resizing" array in C++ - c++

So I'm trying to create a function that "resizes" a member array to a new size passed as an argument. By "resize", I mean that it should set the member array to a new array with the new size, copy over the elements from the old array, and then deallocate the memory associated with the old array. Here's what I have so far:
void MemoryTest::resize(unsigned int new_size) {
if (size == new_size)
return;
int* oldPtr = elements;
elements = new int[new_size + 1];
for (int i = 0; i < (new_size < size) ? new_size : size; i++)
elements[i] = oldPtr[i];
elements[new_size] = '\0';
if (size > new_size)
size = new_size;
delete[] oldPtr; // Deallocate old elements array
}
elements is a private member int* initialized to NULL.
However, when it begins the for loop, the program hangs for awhile before giving an Access Violation for the elements[i] = oldPtr[i] line. Someone please correct me if I'm wrong (which I probably am), but my understanding is that oldPtr should be a pointer pointing to the same initial point as elements. Then, I set elements equal to a new array, so the two are now pointing to two different things. Then I iterate through elements, setting each item equal to its counterpart in the old array.
Also, while I would normally use a vector to avoid situations like this, I'm trying to become more familiar with pointers and memory allocation in C++.
Thanks in advance!

for (int i = 0; i < (new_size < size) ? new_size : size; i++)
should read
for (int i = 0; (i < (new_size < size)) ? new_size : size; i++)
So, for (int i = 0; i < ((new_size < size) ? new_size : size); i++) should correct your code.

Related

How to insert an object in the array of pointers

I have an array of pointers:
Hotel *hotels[size];
for (int i = 0; i < size; ++i)
hotels[i] = new Hotel();
And I want to insert an object in this array after some object with name I know:
cin >> tmp_name;
for (int i = 0; i < size; i++) {
if (hotels[i]->get_name() == tmp_name) {
hotels[size] = new Hotel();
size += 1;
Hotel *tmp_hotel;
tmp_hotel = hotels[i+1];
hotels[i+1]->fillHotel();
for (i = i + 2; i < size; i++) {
hotels[i] = tmp_hotel;
tmp_hotel = hotels[i+1];
}
break;
}
}
What I do wrong?
UPD:
My solution:
cin >> tmp_name;
for (int i = 0, j = 0; i < size; i++, j++) {
new_hotels[j] = hotels[i];
if (hotels[i]->get_name() == tmp_name) {
new_hotels[j+1]->fillHotel();
++j;
system("clear");
}
}
hotels[size] = new Hotel();
++size;
for (int i = 0; i < size; i++) {
hotels[i] = new_hotels[i];
}
I can see different errors in your code.
For example:
Hotel *hotels[size];
size should be a constant expression and something let me think this is not the case. VLA are not part of the C++ standard. In short you cannot allocate dynamic memory on the stack. The proper initialization should be:
Hotel* hotels = new Hotel*[size];
The line in the loop:
hotels[size] = new Hotel();
you're actually accessing out of bounds of your array: size index is some memory is not included in your array and this will produce an undefined behaviour.
Another strange line is the following:
size += 1;
Despite the fact that confirms size is not a constant, you cannot increase your size of vector simply changing that variable. You're actually just changing a variable size, but the allocated memory for your array will be the same.
How resolve?
In order in increase (or change) the size of an array, the solution is almost always to create a new array, copy the old one. In your case that solution is pretty reasonable because you should copy just pointers and not entire objects.
There are a lots of question on S.O. where this topic is, for example here.
Despite of that, I strongly suggest you to use the most practical alternative, that is to use a real C++ code.
The most efficient class is std::vector which is a C++ way to handle dynamic array.
Finally, you should also consider the std::unique_ptr<T> class to handle dynamic memory and pointers.
The final solution will be a class:
std::vector<std::unique_ptr<Hotel>> hotels;

Deleting a string from a dynamic array and making that array one smaller

My class assignment is to create a program using OOP that creates a dynamic array that can act like a vector. My remove entry function is crashing when I run it. After messing around with it for a while I can't seem to make it stop crashing no matter what I do. Here are the instructions for this function in particular.
The function should search dynamicArray for the string.If not found, it returns false. If found, it creates a new dynamic array one element smaller than dynamicArray. It should copy all elements except the input string into the new array, delete dynamicArray, decrement size, and return true.
bool dynamicStringArray::deleteEntry(std::string oldString)
{
for (int i = 0; i < size; i++){
if (dynamicArray[i].compare(oldString) == 0){
std::string* shortArray = new std::string[size - 1];
delete &dynamicArray[i];
for (int j = 0; j < size - 1; j++)
shortArray[j] = dynamicArray[j];
size--;
for (int j = 0; j < size; j++)
dynamicArray[j] = shortArray[j];
return 1;
}
}
return 0;
}
You have a bit of misunderstanding about what
delete &dynamicArray[i];
does.
It does not remove the i-th entry from dynamicArray. It tries to deallocate memory of one objet -- the i-th object. That in itself is cause for undefined behavior.
You may not call delete on a pointer unless it was returned by a call to new.
The second problems is that dynamicArray continues to have that pointer as the i-th element.
Here's an updated if statement that should work.
if (dynamicArray[i].compare(oldString) == 0) {
std::string* shortArray = new std::string[size - 1];
// Copy everything form dynamicArray to shortArray except
// the i-th element.
for (int j = 0; j < i; j++)
{
shortArray[j] = dynamicArray[j];
}
for (int j = i+1; j < size; j++)
{
shortArray[j-1] = dynamicArray[j];
}
// Delete old array
delete dynamicArray;
// Make the newly allocated array the array of
// the object.
dynamicArray = shortArray;
// Decrement the size
--size;
return 1;
}

How to use a stack of pointers to arrays, and access two arrays in the same command?

Just to be clear, this is for a homework assignment. I'm not asking for anyone to do it for me, I'm just stuck on a small portion of it.
I'm asked to implement mergesort, but each new array I make has to be placed in a stack of pointers. In the code below, I'm trying to split up an array recursively, then merge them together. My stack is named ptrs. The merge() function takes two sorted arrays and their sizes.
template <typename T>
T* MergeSort<T>::mergeSort(T arr[], int size) {
int size1 = (int)size/2;
int size2 = size - size1;
//I'll have a base case to cover the arrays of size 1 or 2
ptrs.push(new T[size1]);
for(int i = 0; i < size1; i++) {
ptrs.top()[i] = arr[i];
}
ptrs.push(new T[size2]);
for(int i = 0; i < size2; i++) {
ptrs.top()[i] = arr[i + size1];
}
return merge(mergeSort(TODO, size1), mergeSort(ptrs.top(), size2), size1, size2);
My problem is marked by my TODO. How can I access the first array, if the second one is now on the top of the stack?
Why do you need a stack at all? Since you allocate two new arrays and copy the two portions of the input array, you can recurse on them directly:
T* left = new T[size1];
for(int i = 0; i < size1; i++) //...
T* right = new T[size2];
for(int i = 0; i < size2; i++) /...
T* left_sorted = mergeSort(left, size1);
T* right_sorted = mergeSort(right, size2);
Then merge, being careful to deallocate:
delete[] left;
delete[] right;
T* merged = merge(left_sorted, right_sorted, size1, size2);
delete[] left_sorted;
delete[] right_sorted;
return merged;
If this is allowed by the assignment, I would strongly recommend using std::vector instead of plain arrays + sizes. You could also consider in-place merge to avoid all those allocations.

Why does this array resizing code only work when increasing, not decreasing?

I have a Stack implementation that I'm making in C++. In another question, somebody said that this function, resize(), only works if capacity is greater than size. I tested it and it's true. The program crashes if capacity is less than or equal to size.
I can't seem to realize what is causing it to crash. Could somebody shine some light on this?
template <class Type>
void Stack<Type>::resize(int capacity) {
if(capacity > MAX_SIZE)
capacity = MAX_SIZE;
Type* copy = new Type[capacity];
for (int i = 0; i < N; i++) {
copy[i] = s[i];
}
delete [] s;
s = copy;
size = capacity;
}
s is a Type * array.
N is an int member variable that counts the next open index.
size is an int member variable that keeps track of the array size.
Assuming that N is the size of s (or is otherwise somehow related to it) and N is greater than `capacity, this line:
for (int i = 0; i < N; i++) {
copy[i] = s[i];
}
writes into memory beyond the end of copy. Writing beyond the end of an array is an error.

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;