arrays, removeFirst() not working? - c++

I have created a method that should remove the first element of an array, however when I run my code, the debugger flips out and I'm not sure why.
This is my removeFirst() method:
Loan & ListOfLoans :: removeFirst(){
index = 0;
//determine if the container needs to be shrunk
if((numberOfElements < capacity/4) && (capacity >= 4)){ // shrink container when array is 1/4 full
cout<<"shrinking array! \n";
Loan ** temp = elements;
elements = new Loan * [numberOfElements/2];
//copy temp array to elements
for(int i = 0; i<numberOfElements; i++){
temp[i] = elements[i];
numberOfElements = numberOfElements/2;
delete [] temp;
}
}
numberOfElements--;
return **elements;
}
And my header file for good measure:
#include <iostream>
#include "loan.h"
using namespace std;
class ListOfLoans {
public:
ListOfLoans(int initial_size=4);
~ListOfLoans(void);
void add(Loan & aLoan);
Loan & first() ;
Loan & removeFirst();
// answer the first element from the list and remove it from the list
// if the resulting list is more than three quarters empty release some memory
Loan & removeLast();
// answer the last element from the list and remove it from the list
// if the resulting list is more than three quarters empty release some memory
Loan & next();
int size();
private:
Loan ** elements; //actuall stuff in the array m_pnData;
int numberOfElements; //number of elements in the list stize of the array? m_nLength
int capacity; //size of the available array memory
int index; //used to help with the iteration
};

Try moving delete [] temp; under the for loop.
It looks like one issue may be that delete [] temp; is being called repeatedly within the for loop.
The first iteration through the loop, the memory associated with temp will freed. Subsequent iterations through the loop will access the freed memory.
There may be other issues. It would be very helpful to see the output from the debugger.

There are many issues with this code. Here is an annotated copy.
// Return by reference cannot be used if you are removing the element.
// This looks like a Java-ism.
Loan & ListOfLoans :: removeFirst(){
// unused variable
index = 0;
if((numberOfElements < capacity/4) && (capacity >= 4)){
cout<<"shrinking array! \n";
Loan ** temp = elements;
// you are allocating an array of size numberOfElements/2...
elements = new Loan * [numberOfElements/2];
// then accessing elements which are way past its end.
for(int i = 0; i<numberOfElements; i++){
temp[i] = elements[i];
// you are halving the array size in every iteration
numberOfElements = numberOfElements/2;
// you are deleting temp in every iteration,
// causing double-frees
delete [] temp;
}
}
// if the array does not need to be shrunk,
// you are actually removing the last element.
// the removed element is not freed and is leaking.
numberOfElements--;
// you are returning the first element,
// which is not removed.
return **elements;
}
I would strongly recommend to replace ListOfLoans with an STL container, such as std::deque. If you can't do this, here is a minimal fixed version.
Loan ListOfLoans::removeFirst() {
Loan to_return;
if (numberOfElements == 0) {
return to_return; // return default value, there is nothing to remove
}
if ((numberOfElements < capacity/4) && (capacity >= 4)) {
Loan **old = elements;
capacity = capacity / 2;
elements = new Loan*[capacity];
for (int i=0; i < numberOfElements - 1; ++i) {
elements[i] = old[i+1];
}
to_return = *old[0];
delete old[0];
delete[] old;
} else {
to_return = *elements[0];
delete elements[0];
for (int i=0; i < numberOfElements - 1; ++i) {
elements[i] = elements[i+1];
}
}
--numberOfElements;
return to_return;
}

Related

Creating a custom vector class. Push_back function only working for the first value

In my Comp Sci class, we are learning how to make our own vector class. We will eventually store our custom made string class objects in a custom made vector class. I wanted to try and build a vector class of integers beforehand for simplicity.
So far, I have a default constructor that initializes my pointer to an empty array and sets the size to 0. Then I try to append some values using my push_back function and then check to make sure it was done correctly.
When I do std::cout << v[0] << std::endl;
I get the correct output (10). However, if I call push_back again and then call v[1] I get 0.
I feel like I am not allocating memory correctly in my push_back function but I am not sure.
Thanks for any advice!
[part 1][1]
[part 2][2]
sorry if my formatting is wrong I am new to posting here.
class:
class myVector
{
private:
int *data; //will point to an array of ints
size_t size; //determins the size of array
public:
myVector(); // default constructor
void push_back(int); // appends an integer to the vector
int operator[](size_t);
size_t sizeOf();
};
main:
int main()
{
myVector v;
v.push_back(10);
std::cout << v.sizeOf() << std::endl;
v.push_back(14);
std::cout << v.sizeOf() << std::endl;
std::cout << v[1] << std::endl;
return 0;
}
member functions:
size_t myVector::sizeOf()
{
return size;
}
int myVector::operator[](size_t location)
{
return this->data[location]; //this will return the value at data +
//location
}
myVector::myVector()
{
this->data = new int[0]; //initialize the data to an empty array of
//ints
size = 0; //initialize the size to 0
}
void myVector::push_back(int val)
{
if(size == 0) //if size == 0, create a new array with 1 extra index
{
++size;
delete [] this->data;
this->data = new int[size];
this->data[0] = val;
}
else
{
++size;
int *temp = new int[size - 1];
for(int i = 0; i != (size - 1); i++)
{
temp[i] = this->data[i];
}
delete [] this->data;
this->data = new int[size];
for(int i = 0; i != (size - 1); i++)
{
this->data[i] = temp[i];
}
this->data[size] = val;
delete [] temp;
}
}
In your code:
this->data[size] = val;
you are going outside of the allocated array.
Same in the previous loop (in its last iteration):
for(int i = 0; i != (size - 1); i++)
{
this->data[i] = temp[i];
}
There are a few problems.
It does not look like you need a special case for 0 sized vector
you do not allocate enough memory:
Example, if size is one, you hit this case, then size becomes 2, and you allocate a buffer of ... 1.
else
{
++size;
int *temp = new int[size - 1];
for(int i = 0; i != (size - 1); i++)
{
temp[i] = this->data[i];
}
Tip: use ```for (int i = 0; i < size; ++i)``` and ```new int[size]```
you go out of bounds after your loop. If you allocate [size] bytes, then (size-1) is the last valid index.
you copy data into temp, then copy temp into ANOTHER allocation. You don't need to do that. Just assign this->data = temp; The whole second loop is needless, and don't delete temp at the end.
Its not necessary to a lot of new and delete operations and loops. I fixed and cleaned your two functions.
myVector::myVector()
{
this->data = new int[1]; //initialize the data to an empty array of
//ints
size = 0; //initialize the size to 0
}
void myVector::push_back(int val)
{
if(size == 0) //if size == 0, create a new array with 1 extra index
{
++size;
this->data[0] = val;
}
else
{
++size;
int *temp = new int[size];
for(int i = 0; i != (size-1); ++i)
{
temp[i] = this->data[i];
}
delete [] this->data;
this->data = temp;
this->data[size-1]=val;
}
}
in push_back function allocate a new array with new size and copy data from existing array. After deleting existing array and we see this->data can't point to valid location. Assign the new array's address to this->data and we access existing data and size increased +1. Last we assign parameter val to end of array(size-1).

Resizing string array in hash-table

I'm learning hashing right now. I am trying to resize my hash-table when it is >=80% filled. But every time i try to resize it, i get undefined behaviour or it crashes.
I tried to make a new String array with more fields and then i deleted the old one but that wasn't working.
hashtable.h
class hashtable
{
public:
hashtable();
void insert(string);
void resize_array();
int hashfunction(string str);
string* getArray();
private:
int elemts_in_array;
int table_size;
string* T;
};
hashtable.cpp
hashtable::hashtable()
{
// your code (start with a capacity of 10)
table_size = 10;
elemts_in_array = 0;
string *array = new string[table_size];
T = array;
}
void hashtable::insert(string key)
{
string* array = getArray();
int hkey=hashfunction(key);
float filled = float(elemts_in_array)/float(table_size);
// When the array is more than 80% filled resize it and double the table_size
if(filled >= 0.8)
{
cout << "Resizing Array.." << endl;
resize_array();
}
for(int i=0; i<table_size;i++)
{
// if the field is empty insert it, else go +1
if(array[(hkey+i)%table_size] == "")
{
array[(hkey+i)%table_size] = key;
elemts_in_array++;
break;
}
if(array[(hkey+i)%table_size] == key)
{
// it is the same element
break;
}
}
}
void hashtable::resize_array()
{
int old_table_size =table_size;
table_size*=2; // double the size of the hashtable
string* old_array= new string[table_size]; // save the old array entries
old_array = T;
// Apply the old entries in old_array
for(int i=0; i<table_size;i++)
{
old_array[i]= T[i];
}
//create a new array with double size
string *new_array = new string[table_size];
//delete the old T
delete[] T;
T = new_array;
//re-hash the old entries into the new array with double size (HERE I GOT THE ISSUES)
for(int i=0; i<table_size/2; i++)
{
insert(old_array[i]);
}
}
sometimes my program went into a loop or it crashed. I really don't know why it is not working.
If you step through your program's execution with your debugger, you will probably spot an issue with your resize_array function.
When it copies the old table entries back to the newly allocated array, it uses the insert function. This has some problems:
you might not get back the same ordering of the original values, due to the collision resolution;
the insert function increases the table size, thus it will end up thinking it has twice as many entries as you originally inserted.
Now, the crash could happen because insert will hit the table-increase limit again. The cycle repeats until you either get a stack overflow or you run out of memory.
The proper way to copy back in your strings is this:
for(int i = 0; i < table_size / 2; i++)
{
T[i] = old_array[i];
}
But then there's another problem that can crash before any of this happens. You first saved your values like this:
for(int i=0; i<table_size;i++)
{
old_array[i]= T[i];
}
Note that table_size has already been doubled and so you are going to access past the end of T. You should have looped on old_table_size instead.
You also have some needless copying. If you are going to reallocate T, then just do this:
void hashtable::resize_array()
{
int old_table_size = table_size;
table_size *= 2;
string* old_T = T;
T = new string[table_size];
for (int i = 0; i < old_table_size; i++)
{
std::swap(T[i], old_T[i]); // or in C++11 assign with std::move
}
delete[] old_T;
}

How to "change the size" of an array [Pointers being used]

So I have to implement a stack using an array built in a class, and if the "stack" ever fills up, I am supposed to increase the size of the array which I attempted, and failed. So I am just curious as to what I need to change in order to make this work.
class AbstractStack
{
private:
Type elements; // elements in the array
Type max;
Type *s;
public:
AbstractStack(Type num) { //CONSTRUCTOR
elements= -1;
this->max = num;
s = new Type[max];
}
/* bunch of code that does not apply to this issue
*/
void push ( Type e ) {
if (elements + 1 == max) {
cout << "Stack at max size, WIll increase size of array and add item" << endl;
Type *temp = new Type[max + (max/2)];
for (int i = 0; i < elements+1; i++) {
temp[i] = s[i];
}
s = temp;
delete temp;
elements++;
s[elements] ;
return;
}
else {
elements++;
s[elements] = e;
}
}
When I take the size of this new s, I get the correct size of 1 larger than before because this function is only called when trying to add 1 element to the full stack, but when I attempt to use the top function, it just gives me 0 then I get like 50 lines of error codes starting in:
*** Error in `./a.out': double free or corruption (top): 0x0000000000c53cf0 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x7c619)[0x7fa34a270619]
./a.out[0x400c38]
./a.out[0x400b48]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x7fa34a215c05]
./a.out[0x400979]
Type elements; // elements in the array
Type max;
These are both just ints, or unsigneds, or size_ts, or whatever you prefer for counting. They have nothing to do with Type whatsoever.
void push ( Type e ) {
if (elements + 1 == max) {
cout << "Stack at max size, WIll increase size of array and add item" << endl;
Type *temp = new Type[max + (max/2)];
After this you should increase max to max*3/2.
for (int i = 0; i < elements+1; i++) {
Loop condition should be i < elements. You are using element zero, and element[elements] does not exist yet.
temp[i] = s[i];
}
s = temp;
delete temp;
Last two lines should be delete[] s followed by s = temp.
elements++;
s[elements] ;
Last two lines should be s[elements++] = e;
return;
return is redundant here.
}
else {
elements++;
s[elements] = e;
Again, the last two lines should be s[elements++] = e;
}
}
Corrected and simplified version:
int elements;
int max;
// ...
void push ( Type e ) {
if (elements + 1 == max) {
cout << "Stack at max size, WIll increase size of array and add item" << endl;
max += max/2;
Type *temp = new Type[max];
for (int i = 0; i < elements; i++) {
temp[i] = s[i];
}
delete[] s;
s = temp;
}
s[elements++] = e;
}
You have to delete the old array (s) instead of the new (temp):
delete[] s;
s = temp;
Also: make sure that your class has a proper destructor (deleting s).

Unitialized local variable and help correcting

I am learning about pointers and the new operator in class.
In my readArray function I am to read in a size. Use the size to dynamically create an integer array. Then assign the array to a pointer, fill it, and return the size and array.
I believe I've gotten that part corrected and fixed but when I try to sort the array, i get the error "uninitialized local variable temp used."
The problem is though I get that error when I am trying to intialize it.
Any help appreciated thank you. Seeing my errors is very helpful for me.
#include <iostream>
using namespace std;
int* readArray(int&);
void sortArray(int *, const int * );
int main ()
{
int size = 0;
int *arrPTR = readArray(size);
const int *sizePTR = &size;
sortArray(arrPTR, sizePTR);
cout<<arrPTR[1]<<arrPTR[2]<<arrPTR[3]<<arrPTR[4];
system("pause");
return 0;
}
int* readArray(int &size)
{
cout<<"Enter a number for size of array.\n";
cin>>size;
int *arrPTR = new int[size];
for(int count = 0; count < (size-1); count++)
{
cout<<"Enter positive numbers to completely fill the array.\n";
cin>>*(arrPTR+count);
}
return arrPTR;
}
void sortArray(int *arrPTR, const int *sizePTR)
{
int *temp;
bool *swap;
do
{
swap = false;
for(int count = 0; count < (*sizePTR - 1); count++)
{
if(arrPTR[count] > arrPTR[count+1])
{
*temp = arrPTR[count];
arrPTR[count] = arrPTR[count+1];
arrPTR[count+1] = *temp;
*swap = true;
}
}
}while (swap);
}
You make temp an int pointer (uninitiialized), and then set the thing it points at (anything/nothing) to arrPTR[ccount]. Since you are using temp only to swap, it should be the same type as those being swapped, in this case: an int.
If it absolutely must be a pointer (there is no good reason for this, it's slow, confusing, adds potential for errors, and adds potential for memory leaks):
int *temp = new int; //make an int for the pointer to point at
bool *swap = new bool; //make an bool for the pointer to point at
do
{
//your code
}while (swap);
delete temp;
delete swap;
You declared temp as a pointer. You need to allocate it on the heap before dereferencing and assigning to it later. However perhaps a variable on the stack would be preferable?
FYI: You should be aware of the memory leak in readArray as well which is leaving callers responsible for calling delete []
Edit: I hope this will help clear up some of the other problems.
#include <iostream>
int* readArray(int&);
void sortArray(int*, int);
int main ()
{
int size(0); // use stack when possible
int *arrPTR = readArray(size);
sortArray(arrPTR, size);
// arrays are zero based index so loop from 0 to size
for (int index(0); index < size; ++index)
std::cout << arrPTR[index];
delete [] arrPTR; // remember to delete array or we have a memory leak!
// note: because we did new[] for an array we match it with delete[]
// if we just did new we would match it with delete
system("pause");
return 0;
}
int* readArray(int& size)
{
std::cout << "Enter a number for size of array.\n";
std::cin >> size;
int *arrPTR = new int[size]; // all news must be deleted!
// prefer pre-increment to post-increment where you can
for(int count(0); count < size; ++count)
{
std::cout << "Enter positive numbers to completely fill the array.\n";
std::cin >> arrPTR[count];
}
return arrPTR;
}
// passing size by value is fine (it may be smaller than pointer on some architectures)
void sortArray(int *arrPTR, int size)
{
// you may want to check if size >= 2 for sanity
// we do the two loops to avoid going out of bounds of array on last iteration
for(int i(0); i < size-1; ++i) // the first to compare (all except last)
{
for(int j(i+1); j < size; ++j) // the second to compare (all except first)
{
// do comparison
if (arrPTR[i] > arrPTR[j]) // from smallest to biggest (use < to go from biggest to smallest)
{
// swap if needed
int temp(arrPTR[i]); // put this on stack
arrPTR[i] = arrPTR[j];
arrPTR[j] = temp;
}
}
}
}
temp is a "pointer to int, which you're not initializing. When you say *temp = ... you're actually assigning to whatever temp happens to be pointing, but since you haven't told it what to point to, it can write pretty much anywhere in the address space of your program.
Because of the way you're using them, it seems that temp and swap shouldn't be pointers at all, just a plain int and bool.
You didn't initialize the temp pointer do when you dereference it you are writing to a random part of memory. Temp doesn't need to be a pointer, it can just be an int. Just replace EVERY instance of *temp with temp.

Inserting an element into an array

How can I make an inset method that will add a number into the array in the correct order?
void addElement(int table[], int element, int length) {
int x = 0;
int temporary=0;
cout<<length<<endl;
if(length == 1) {
table[0] = element;
}
else {
if(length == 2) {
if (table[0] > element) {
int temp = table[0];
table[0] = element;
table[1] = temp;
}
else {
table[1] = element;
}
}
else {
for(int i = 0; i< length && x == 0; i++) {
if(element<table[i] && element>=table[i-1]) {
for(int y = i; y<length; y++) {
temporary = table[y+2];
int temp = table[y];
table[y] = element;
table[y+1] = table
}
}
}
}
}
}
This is as far as I have gotten. In my main class I have worked it out so that array is increased by 1. So there is one open space at the end of the array for everything to be pushed back by 1.
You can scan the array from back to front, moving values up until you find the correct insertion point.
void addElement(int *table, int element, int length)
{
int i = length - 1;
for (; i > 0 && table[i-1] > element; --i)
{
table[i] = table[i-1];
}
table[i] = element;
}
Write a shiftElements function, write a findIndexOfFirstGreaterThan function, then in addElement - find the index, if -1 then put in last slot, else shift elements using index, then a[index]=elem;
Draw yourself an example, then work out a list of very simple steps required to do what you want.
Then write code that does those steps.
Im not sure if this is what your looking for, but I think you want something that adds an element depending on its integer value. Also, I do not have access to a compiler at this moment so there might be a couple of errors. The code below is just written to give you a brief idea of what you could do, but probably not a perfect solution to your problem.
int addElement (int element, int array [], int length)
{
vector <int> vectorOfInts; //vector to store current order of ints
vector <int> vectorOfArrangedInts; //vector to store arranged order
for (int counter = 0; counter < length; counter ++) //loop to fill the array with values
{
vectorOfInts.push_back (array [counter]);
}
for (int counter = 0; counter < vectorOfInts.length(); counter ++) //loop through all elements
{
int temp = 0; //stores temp value of biggest number found at a specific moment
int elementIndex; //stores indexes
for (int counterTwo = 0; counterTwo < vectorOfInts.length(); counterTwo ++) //loop through all elements to find the biggest array
{
if (vectorOfInts.at (counterTwo) >= temp) //if value is bigger than current biggest number
{
temp = vectorOfInts.at (counterTwo); //change temp value
elementIndex = counterTwo; //remember index
}
}
vectorOfArrangedInts.push_back (vectorOfInts.at(elementIndex)); //add the biggest number to the arranged values
vectorOfInts.erase (vectorOfInts.begin() + elementIndex); //remove the biggest element
}