Ordered Array. Resize does not allow ordered elements - c++

i am making an ordered array. Where the elements are in order. Example 1,2,3,4,5,6,77,89,100,201. I ask the user to enter in the size of the array. This is fine and the push function will put the elements in ordered. But when the arrayList is resized,The elements are no longer being allocated in an ordered fashion.
Here is my code:
//-------------------------------------------------------
// Name: Array::Resize
// Description: Resize the array to a new size.
// Arguments: p_size. The new size of the Array.
//-------------------------------------------------------
void Resize(int p_size)//resizes the array to the size of p_size
{
cout << "Did i get this far ";
if(p_size < 0)//checks if new size is less than 0
{
cout << "ERROR! Size of an array can not be less than 0!" << endl;
}
else//else its ok to continue
{
Datatype* newArray = new Datatype[p_size];//creates a pointer newArray that points at a new array
if(newArray == 0)
{
return;
}
cout << "Did i get this far ";
int min;
if(p_size < size)//checks the if the new array is smaller than the old one
min = p_size;
else//else its going to be bigger
min = size;
cout << "Did i get this far ";
int index;
int temp = num_elements;//puts num_elements into a temporary variable called temp
num_elements = 0;//num_elements is set to 0
for(index = 0; index < min; index++)
{
newArray[index] = m_array[index];//places everything from the old array into the new array that will fit.
if(num_elements < temp)//if the num_elements is less than temp(the original num_elements)
{
num_elements++;//increment num_elements. This will keep incrementing to create the new num_elements based the number of elements cut off in the resize
}
}
size = p_size;//sets the old size to be equal to the new size
cout << "Did i get this far ";
if(m_array != 0)
cout << "\nI am just about to delete ";
//delete[] m_array;//deletes the old array
m_array = newArray;//makes m_array point at the new array
newArray = 0;//makes newArray a null pointer
}
}
//---------------------------------------------------------------------------------------
// Name: Push
// Description:
//---------------------------------------------------------------------------------------
void push(Datatype p_item)
{
if(num_elements == size)//checks if the array is full and needs to be resized
{
Resize(size + g_size);//calls the resize function
}
int pos = num_elements;
for(int x=0;x<num_elements;x++)
{
if(p_item < m_array[x])
{
pos=x;
}
}
//loops through the array from high to low moving all values to the right
//to make space for the passed in value until it gets to the right place
for(int index = num_elements; index >= pos; index--)
{
m_array[index] = m_array[index-1];//moves the values to the right
}
m_array[pos] = p_item;//the passed in value is positioned into its ordered position
num_elements++;
cout<< "Num Elements " << num_elements;
cout<< "Size " <<size;
}
//--------------------------------------------------------------------------------------------
// Name: template <class Datatype>
// Description:
//--------------------------------
template <class Datatype>
//--------------------------------------------------------------------------------------------
// Class: OrderedArray.
//--------------------------------------------------------------------------------------------
class OrderedArray
{
//--------------------------------------------------------------------------------------------
// Member Variables.
//--------------------------------------------------------------------------------------------
private:
Datatype* m_array;
int size;
int g_size;
int num_elements; //Counter for the number of elements in the Array.
//--------------------------------------------------------------------------------------------
// Name: Constructor.
// Description: Constructs the Array.
//--------------------------------------------------------------------------------------------
OrderedArray(int p_size)
{
//Sets the Array size.
m_array = new Datatype[p_size];
size = p_size;
grow_size = 1;
//How many elements are in the Array.
num_elements = 0;
}
Any help would be much appreciated.

I suggest using copies of last element of your m as new elements instead of default-constructed instances. So the last elements will be grater or equal to all preceding elements of the array.

Related

Error while trying to declare a push back method in a vector class that i created

I created a class that mimics the action of C++ vector by creating a dynamic array, I try to create a push back method for that class which first checks if the array is filled, if so it will:
1- Copy the contents of current array to a temporary array with the double size
2- Delete the old dynamic array
3- Create a new dynamic array with the double size of the old array (same size of temporary array)
4- Copy contents of the temporary array to the new dynamic array
the error is while I use the following code, I can only double the size of array once, then it throws to error:
HEAP[ConsoleApplication1.exe]: Invalid address specified to RtlValidateHeap( 016C0000, 016CDB98 )
ConsoleApplication1.exe has triggered a breakpoint.
#include <iostream>
using namespace std;
class SimpleVector {
private:
int* item; //pointer to the dynamic array (the vector)
int size;
int numElements;
public:
SimpleVector(int size) {
this->size = size;
this->numElements = 0;
this->item = new int[this->size];
}
SimpleVector():SimpleVector(10){}
void pushBack(int element) {
//check for overflow
if (numElements >= size) {
int newSize = size * 2;
int* temp = new int[newSize]; // temporary array with the double size to hold old array elements
for (int i = 0; i < numElements; i++) {
temp[i] = item[i];
}
delete[] item;
size = newSize;
//****ERROR IS IN THIS PART****
int* item = new int[size];
for (int i = 0; i < numElements; i++) {
item[i] = temp[i];
}
//****END OF THE PART CONTAINING ERROR****
item[numElements++] = element;
cout << "Added: " << element << endl;
cout << "Size is: " << size << endl;
}
else {
item[numElements++] = element;
cout << "Added: " << element << endl;
cout << "Size is: " << size << endl;
}
}
};
int main() {
SimpleVector v1(2);
v1.pushBack(1);
v1.pushBack(2);
v1.pushBack(3);
v1.pushBack(4);
v1.pushBack(5);
v1.pushBack(6);
v1.pushBack(7);
return 0;
}
This program pushs the first 4 items and then throws into error when trying to double the size form to 8
when I just replace that part containing error with:
item = temp
it works fine, but I can't understand why this happens.
Your code has several problems. I suggest you read about how to properly comply with Rule of Three/Five/Zero , which I'm not going to cover here. I only imagine this is for some nefarious academic purpose, so I will try to be brief, but please read the linked article.
That said, this:
int *item = new int[size];
for (int i = 0; i < numElements; i++)
{
item[i] = temp[i];
}
is pointless. This starts a cascade of bad actions that only gets worse as it rolls along.
You already have a member variable item. This code declares a local variable named item whose name hides the member item. Therefore the initialized value from the new operator is stored in the local, not the member.
That memory now pointed to by the local var item (not the member) is lost on exit of the function, since nothing but the local item ever points to it.
That additional allocation is pointless to begin with. You already made a new vector copy, pointed to by temp, and already copied all the legitimate items from memver-var item memory to temp memory. The code as-written leaks that temp allocation as well.
You destroy the member-var item memory, leaving the pointer now dangling, and any usage thereafter by dereference or eval invokes undefined behavior.
So, in summary, you make a valuable extended copy, leak it, make a worthless copy, leak it too, and end up leaving with a member variable that is no longer pointing at anything defined.
That entire function could look more like this:
void pushBack(int element)
{
// check for overflow
if (numElements >= size)
{
int newSize = size * 2;
int *temp = new int[newSize];
for (int i = 0; i < numElements; i++)
{
temp[i] = item[i];
}
delete[] item;
size = newSize;
item = temp;
}
item[numElements++] = element;
cout << "Added: " << element << endl;
cout << "Size is: " << size << endl;
}

How to write a procedure to modify the elements and size of a dynamic array without knowing the size?

The following is a question from an exam in programming I had recently. Neither me nor the other students have found a way of solving it. The professor says it is possible, however refused to tell us what the solution is. The question:
Write a procedure with a header of:
void ArrayUpdate( int ??? array, int ??? delAmount, int ??? addAmout)
The procedure is used to modify elements of a dynamic array passed through the first argument.
The procedure should remove the delAmount of the first cells from the array. It should also add addAmount of elements to the back of the array with whole numbers read from std::cin.
The "???" need to be replaced or removed.
Square brackets "[ ]" can only be used with new or delete.
Only iostream and fstream may be included. (fstream was needed for another question, so it may not be needed here.)
"The procedure is used to modify elements of a dynamic array passed through the first argument." It does not say how the array is organized. The first element, as #user4581301 suggested, might be the size of the array. In other words, the first element of the array is at position 1, not 0. This is most likely what your teacher had in mind. The purpose is to teach you pointers/references and the array layout.
Creating an array:
void CreateArray( int*& array, int size )
{
array = new int[ size + 1 ];
array[ 0 ] = size;
}
You may use int** instead of int*&, but it is harder to write/read.
Retrieving the size:
int ArraySize( int* array )
{
return *array;
}
Usage:
int* array;
CreateArray( array, 10 );
//...
for ( int i = 1; i <= ArraySize(array); ++i )
// ...
Function signature:
void ArrayUpdate( int*& array, int delAmount, int addAmout);
Here's my hack-cut at the problem. It's very similar to ZDF's, but it adds the array's capacity to the book-keeping and lies and hides the book-keeping by giving the caller a pointer to the middle of the array rather than the beginning. This allows the user to use the array as a regular array, but will crash if they try to delete it themselves.
Comments embedded where I figured more explanation was required.
//Magic numbers are evil.
constexpr int bookkeeping = 2;
constexpr int sizeOff = -2;
constexpr int capOff = -1;
void ArrayUpdate( int *& array, int delAmount, int addAmount)
{
int size;
int capacity;
// can't do jack with a non-existent array, so let's make sure we have one.
if (array != nullptr)
{
size = *(array + sizeOff);
capacity = *(array + capOff);
}
else
{
size = 0;
capacity = 0;
}
if (delAmount > size) // can't delete more than we have.
{
delAmount = size;
// alternative: freak out here. Abort, throw exception, whatever
}
int * to; // track where data goes to
int * temp; // location of new buffer, if resized
bool resized;
int newsize =size + addAmount - delAmount;
if (newsize > capacity)
{
capacity *=2;
if (capacity < newsize)
{
capacity = newsize;
}
temp = new int[capacity+bookkeeping];
to = temp + bookkeeping; // point to where we want data to go:
// after the book-keeping.
resized = true;
}
else
{
to = array;
resized = false;
}
// use std::copy or memcpy here, but since we're not allowed the appropriate
// headers, here comes ol' brute force!
if (delAmount || resized) // need to copy old data around
{
for (int index = delAmount; index < size; index++)
{
*to++ = *(array + index);
}
}
// add new data
for (int count = 0; count < addAmount; count++)
{
if (std::cin >> *to) // always test to make sure you got good input
{
to++;
}
else
{ // Bad input. Clean up
std::cin.clear();
// normally I'd use cin.ignore(numeric_limits<streamsize>::max(), '\n')
// here to kill all the remaining user input, but no <limits>
std::cin.ignore(1000, '\n');
// might also want to just read and discard until you find the
// first whitespace. That's can be done easily by >> to a std::string,
// but no string header allowed.
}
}
if (resized)
{
if (array != nullptr) // normally deleting nullptr is safe, but not when
// you're going to modify it with an offset
{
delete[] (array - bookkeeping);
}
array = temp + bookkeeping; // array hides the extra book-keeping
*(array + capOff) = capacity;
}
if (array != nullptr)
{
*(array + sizeOff) = newsize;
}
}
Not exhaustively tested. May be a bug or two in there.
For completeness, here's test code and a Free Array routine:
void FreeArray(int * array)
{
delete[] (array - bookkeeping);
}
void printarray(const int * array)
{
int size;
int capacity;
if (array != nullptr)
{
size = *(array + sizeOff);
capacity = *(array + capOff);
}
else
{
size = 0;
capacity = 0;
}
std::cout << "Size: " << size <<"\nCapacity: "<< capacity << '\n';
for (int index = 0; index < size; index++)
{
std::cout << array[index] << ' ';
}
std::cout << std::endl;
}
int main()
{
int * array = nullptr;
printarray(array);
ArrayUpdate(array, 5, 0);
printarray(array);
ArrayUpdate(array, 5, 5);
printarray(array);
ArrayUpdate(array, 5, 5);
printarray(array);
ArrayUpdate(array, 0, 5);
printarray(array);
ArrayUpdate(array, 5, 0);
printarray(array);
}
If "???" can be replaced by whatever you want, so you can pass to your function a pointer to an int, or a pointer to pointer to int, etc...
So the trick in C++ when dealing with memory management, or range, is to store 2 pointers one to the begin of the array and one to its end:
//a range:
int* limits[2];
int ** array = limits;
Then if you change the size of the range inside a function you must pass it by reference:
void ArrayUpdate( int ** array, int delAmount, int addAmout){
int* begin = array[0];
int* end = array[1];
//end so on
}

Pushing element to dynamically allocated pointer array int C++

[EDIT 1] I'll preface by saying that for this project, I am required to "Create a container class" where I can push, pop, and retrieve elements from a list. I am supposed to use pointers, and must write the functions for pushing, popping, etc. [/EDIT 1]
I am having difficulty pushing an element to a dynamically allocated pointer array. I am able to initially create an array just fine. You can see from my comments my thought process for how I think I should be able to add to the array:
1) create new array with room for the one new element;
2) add the new element to index 0;
3) copy the old array into the rest of the new array;
4) delete old array;
5) set the new array as the value of the pointer
I have the following three files:
IntegerList.h:
/**
*IntegerList.h
*/
#ifndef IntegerList_H
#define IntegerList_H
class IntegerList
{
private:
int * pArray;
int length;
public:
IntegerList(); // default constructor
void createArray(int howlong);
int getValue(int index);
void deleteArray();
void pushFront(int element);
};
#endif
IntegerList.cpp:
/**
* IntegerList.cpp
*/
#include "IntegerList.h"
#include <iostream>
using namespace std;
// IntegerList constructor:
IntegerList::IntegerList()
{
pArray = 0;
length = 0;
}
// creates an array of length howlong (determined by main.cpp); sets the values
// to equal ten times the index number. For example, if an array of size 4 is
// to be created, then an array with the following values will be created by
// this method: 0, 10, 20, 30. Sets length equal to howlong.
void IntegerList::createArray(int howlong)
{
length = howlong;
pArray = new int[length];
for (int i = 0; i < length; i ++)
pArray[i] = (i*10);
}
int IntegerList::getValue(int index)
{
return pArray[index];
}
void IntegerList::deleteArray()
{
delete[] pArray;
}
// places element at front of array
void IntegerList::pushFront(int element)
{
// create new array with room for the one new element
int newArray[length+1]; // nope
// start by adding the new element
newArray[0] = element;
// copy the old array, put it into the new array starting at index 1 (since
// index 0 is the new element)
for(int i = 0; i < length; i ++)
{
newArray[i+1] = pArray[i];
}
// delete old array
deleteArray();
// set pArray equal to the new array;
pArray = newArray;
// update the value of length
length += 1;
}
And my main file, main.cpp:
#include "IntegerList.h"
#include <iostream>
using namespace std;
int main()
{
// create object
IntegerList myArray;
// create array of length 5
myArray.createArray(5);
// print array
for (int i = 0; i < 5; i ++)
cout << "Element " << i << ". " << myArray.getValue(i) << endl;
// everything works ok so far
// push the number 99 to front
myArray.pushFront(99);
// print array
for (int i = 0; i < 6; i ++)
cout << "Element " << i << ". " << myArray.getValue(i) << endl;
myArray.deleteArray();
}
The first printArray() shows that everything is going as planned. However, after I try to push 99 to the front, things get screwed up :(
Here is the output I'm getting:
Element 0. 0
Element 1. 10
Element 2. 20
Element 3. 30
Element 4. 40
Element 0. 99
Element 1. 0
Element 2. 2130567168
Element 3. 4486648
Element 4. 2686508
Element 5. 4201772
Note that in the second printout, the first two elements appear to have the value that I intended for them to have.
Any suggestions?
I'm not sure if you can force your way to make static arrays of variable length, but it's in violation of standard.
int newArray[length+1];
will not work. Make it
int * newArray = new int[length+1];
instead.
As others in comments said, reallocating an array after every single insert is extremely inefficient and tedious work. Consider using some of these:
std::vector
std::stack (as you're inserting on the beginning of your container)
std::list
your very own linked list
I rewrote the code for pushing and got it to work properly. Revised code is below. Notice I had to assign the values form the tempArray back into the "original" array (pArray), not the address of tempArray.
void IntegerList::push(int value){
// when this method is called to push a value onto an empty array, that is,
// when length = 0, it first creates an array of length 1
if(length == 0)
pArray = new int[1];
// create temp array
int * tempArray = new int[length+1];
// add new value to index 0
tempArray[0] = value;
// add old elements
for(int i = 0; i < length; i++)
tempArray[i+1] = pArray[i];
delete[] pArray;
// initialize pArray with proper size
pArray = new int[length+1];
// copy elements of tempArray into pArray
for(int i = 0; i < length+1; i++)
pArray[i] = tempArray[i];
delete[] tempArray;
length += 1;
} // end push

C++ - Ordered ArrayList

I have an ordered arrayList. Where elements are to be ordered in 1,2,3,4,5,6.
At the moment the push function is not working. It will insert an element, but there is a problem which i cannot figure out. The push will work once you insert an incremented number... So like 1,2,3,4,5 but will not work once i insert like this 5,2,4,3,2,1.
Can anyone help me with this?
Here is my code:
Initialisation
template <class Datatype>
//--------------------------------------------------------------------------------------------
// Class: OrderedArray.
//--------------------------------------------------------------------------------------------
class OrderedArray
{
//--------------------------------------------------------------------------------------------
// Member Variables.
//--------------------------------------------------------------------------------------------
private:
Datatype* m_array;
int size;
int g_size;
int num_elements;
//---------------------------------------------------------------------------------------
// Name: Print Function:
// Description: To print out all elemenst in the Array.
//---------------------------------------------------------------------------------------
void print()
{
for(int i=0;i< size;i++)
{
cout << "Position: " <<m_array[i]<<endl;
}
}
//---------------------------------------------------------------------------------------
// Name: Resize Function:
// Description: To resize the Array.
//---------------------------------------------------------------------------------------
void Resize(int p_size)//resizes the array to the size of p_size
{
if(p_size < 0)//checks if new size is less than 0
{
cout << "ERROR! Size of an array can not be less than 0!" << endl;
}
else//else its ok to continue
{
Datatype* newArray = new Datatype[p_size];//creates a pointer newArray that points at a new array
if(newArray == 0)
return;
int min;
if(p_size < m_size)//checks the if the new array is smaller than the old one
min = p_size;
else//else its going to be bigger
min = m_size;
int index;
int temp = num_elements;//puts num_elements into a temporary variable called temp
num_elements = 0;//num_elements is set to 0
for(index = 0; index < min; index++)
{
newArray[index] = m_array[index];//places everything from the old array into the new array that will fit.
if(num_elements < temp)//if the num_elements is less than temp(the original num_elements)
{
num_elements++;//increment num_elements. This will keep incrementing to create the new num_elements based the number of elements cut off in the resize
}
}
m_size = p_size;//sets the old size to be equal to the new size
if(m_array != 0)
delete[] m_array;//deletes the old array
m_array = newArray;//makes m_array point at the new array
newArray = 0;//makes newArray a null pointer
}
}
//---------------------------------------------------------------------------------------
// Name: Push
// Description:
//---------------------------------------------------------------------------------------
void push(Datatype p_item)
{
if(num_elements == size)//checks if the array is full and needs to be resized
{
Resize(size + g_size);//calls the resize function
}
int pos = num_elements;
for(int x=0;x<num_elements;x++)
{
if(p_item < m_array[x])
pos=x;
break;
}
//loops through the array from high to low moving all values to the right
//to make space for the passed in value until it gets to the right place
for(int index = num_elements; index >= pos; index--)
{
m_array[index] = m_array[index-1];//moves the values to the right
}
m_array[pos] = p_item;//the passed in value is positioned into its ordered position
num_elements++;
cout<< "Num Elements " << num_elements;
cout<< "Size " <<size;
}
I think I found the beginning of the problem:
for(int x=0;x<num_elements;x++)
{
if(p_item < m_array[x])
pos=x;
}
your pos will always always be at the end of the array that way(assuming the array is properly sorted up to that point). add a break statement to let your loop know when it should stop assigning greater and greater values to pos
for(int x=0;x<num_elements;x++)
{
if(p_item < m_array[x])
{
pos=x;
break;
}
}
your code has some other issues too, for instance
for(int index = num_elements; index > pos; index--)
{
m_array[index] = m_array[index+1];//moves the values to the right
}
actually moves the values left. change the assignment to
for(int index = num_elements; index > pos; index--)
{
m_array[index] = m_array[index-1];//moves the values to the right
}

Deleting array causes run-time error. C++

I have an ordered array list. And in my resize function I create a new array and assign it the values of the old array and then I delete the old array using delete[] arrayname;.
This causes an error at run-time whenever the resize function comes into play. dbgheap.c is called. Has anyone ever seen this before?
Here is my code:
//--------------------------------------------------------------------------------------------
// Name: OrderedArray.h.
// Description: Header file for the use in OrderedArray.cpp.
//--------------------------------------------------------------------------------------------
#ifndef ORDEREDARRAY_H
#define ORDEREDARRAY_H
#include <iostream>
using namespace std;
//--------------------------------------------------------------------------------------------
// Name: template <class Datatype>
// Description:
//--------------------------------------------------------------------------------------------
template <class Datatype>
//--------------------------------------------------------------------------------------------
// Class: OrderedArray.
//--------------------------------------------------------------------------------------------
class OrderedArray
{
//--------------------------------------------------------------------------------------------
// Member Variables.
//--------------------------------------------------------------------------------------------
private:
Datatype* m_array;
int size;
int g_size;
int num_elements; //Counter for the number of elements in the Array.
void Resize(int p_size)//resizes the array to the size of p_size
{
cout << "Did i get this far ";
if(p_size < 0)//checks if new size is less than 0
{
cout << "ERROR! Size of an array can not be less than 0!" << endl;
}
else//else its ok to continue
{
Datatype* newArray = new Datatype[p_size];//creates a pointer newArray that points at a new array
if(newArray == 0)
{
return;
}
cout << "Did i get this far ";
int min;
if(p_size < size)//checks the if the new array is smaller than the old one
min = p_size;
else//else its going to be bigger
min = size;
cout << "Did i get this far ";
int index;
int temp = num_elements;//puts num_elements into a temporary variable called temp
num_elements = 0;//num_elements is set to 0
for(index = 0; index < min; index++)
{
newArray[index] = m_array[index];//places everything from the old array into the new array that will fit.
if(num_elements < temp)//if the num_elements is less than temp(the original num_elements)
{
num_elements++;//increment num_elements. This will keep incrementing to create the new num_elements based the number of elements cut off in the resize
}
}
size = p_size;//sets the old size to be equal to the new size
cout << "Did i get this far ";
if(m_array != 0)
{
cout << "\nI am just about to delete ";
delete[] m_array;//deletes the old array
}
m_array = newArray;//makes m_array point at the new array
newArray = 0;//makes newArray a null pointer
}
}
//---------------------------------------------------------------------------------------
// Name: Push
// Description:
//---------------------------------------------------------------------------------------
void push(Datatype p_item)
{
if(num_elements == size)//checks if the array is full and needs to be resized
{
Resize(size + g_size);//calls the resize function
}
int pos = num_elements;
for(int x=0;x<num_elements;x++)
{
if(p_item < m_array[x])
{
pos=x;
}
}
//loops through the array from high to low moving all values to the right
//to make space for the passed in value until it gets to the right place
for(int index = num_elements; index >= pos; index--)
{
m_array[index] = m_array[index-1];//moves the values to the right
}
m_array[pos] = p_item;//the passed in value is positioned into its ordered position
num_elements++;
cout<< "Num Elements " << num_elements;
cout<< "Size " <<size;
}
//--------------------------------------------------------------------------------------------
// Name: Constructor.
// Description: Constructs the Array.
//--------------------------------------------------------------------------------------------
OrderedArray(int p_size, int grow_size)
{
//Sets the Array size.
m_array = new Datatype[p_size,grow_size];
size = p_size;
g_size = grow_size;
//How many elements are in the Array.
num_elements = 0;
}
//size and g_size are given its value by the user at the start of the program.
There may be some other issue here, but the most obvious thing I can see is this:
for(int index = num_elements; index >= pos; index--)
{
m_array[index] = m_array[index-1];
}
If pos happens to be zero, you will eventually do this:
m_array[0] = m_array[-1];
This problem will show immediately (when num_elements is zero - you haven't shown your constructor, but I do hope that you initialised everything).
Changing >= to > in the loop may solve all your troubles.
Conceptually, you ought to agree with this logic. There is no point moving the item before m_array[pos] forward to m_array[pos] when you are just about to replace it with the new item.
[edit] Now that you have posted your constructor:
m_array = new Datatype[p_size,grow_size];
This will initialise your array with the size grow_size instead of p_size, because of how the comma operator works. Read this: How does the Comma Operator work
Please do this instead:
m_array = new Datatype[p_size];
Your code m_array = new Datatype[p_size,grow_size]; in the constructor should only take one parameter which is the size of the array.
Change to this: m_array = new Datatype[p_size];