Hi i was creating a simple Vector Class for my studies.
Just to store Variable LONG
i kept everything simple. When i build nothing was return error/ warning.
Then after run the program, it works but the program crash.
Code Vector.h
class Vector{
public:
Vector();
void add(long i);
void getData();
private:
long *anArray;
long maxSize;
long position;
void reSize(int i);
};
Vector.cpp
Vector::Vector(){
maxSize = 2;
anArray = new long[maxSize];
position = 0;
}
void Vector::add(long i){
if(position==maxSize-1)
reSize(maxSize * 2);
anArray[position] = i;
position++;
}
void Vector::reSize(int i){
long *temp = new long[maxSize];
for(int i =0; i<maxSize; i++)
{
temp[i] = anArray[i];
}
delete[] anArray;
anArray = temp;
}
void Vector::getData(){
for(int i = 0; i<position; i++)
{
cout << "Element" << i+1 << " : " << anArray[i] << endl;
}
}
Main
int main()
{
Vector vecStore;
for(int i = 0; i < 1000; i++)
{
long a;
vecStore.add(a = i + 1);
}
cout << "GET DATA _________ :: " << endl;
vecStore.getData();
return 0;
}
The program wouldn't crash if the input data small(e.g. 10-20)
but when i change it to 100 or even bigger. the program sometime crash and sometime its not.
Did i make a mistake?
In
void Vector::add(long i){
if(position==maxSize-1)
reSize(maxSize * 2);
anArray[position] = i;
position++;
}
when position==maxSize-1, reSize is called to double the size of the array. Unfortunately, reSize is broken.
void Vector::reSize(int i){
long *temp = new long[maxSize];
for(int i =0; i<maxSize; i++)
{
temp[i] = anArray[i];
}
delete[] anArray;
anArray = temp;
}
The parameter i is never used. This should be the new size of the Vector, but instead the new array is allocated with the same maxSize as the previous array. maxSize goes unchanged.
Back in add, data is stored at position and position is increased by one. This means on the next add position is equal to maxSize, so the check to prevent overrunning the array,
if(position==maxSize-1)
will not do what you want and the program writes outside the bounds of the array. From there, position keeps getting larger, will never be equal to maxSize minus one, and writes even further out of bounds, not that it matters at that point. Undefined Behaviour has already been invoked, and Crom only knows what will happen. Maybe the program crashes, maybe the program crashes later, maybe it does something bizarre, and maybe it even chugs on looking like everything is working just fine.
You want something more along the lines of
void Vector::reSize(int newSize){ // note more descriptive name
long *temp = new long[newSize]; // using new size, not old size
for(int i =0; i<maxSize; i++)
{
temp[i] = anArray[i];
}
delete[] anArray;
anArray = temp;
maxSize = newSize; // store new size.
}
Vector also needs a destructor to clean up anArray, but in order to properly fix this error, here's a bit of recommended reading: What is The Rule of Three?
Related
I am trying to write a class where it starts with a small array to put values in. My objective is if the number of values exceed the capacity, the array expands to fit the remaining values. For example, if I had 5 numbers, the array would expand to accommodate the fifth value.
The object actually creates an array at run time. So when I wrote the function to expand, its actually creating a new array and pointing to it.
Heres the class
class DVec // self expanding array
{
private:
//[0...n-1] are the values, [0..cap-1] exist
int n;
double* a;
int cap;
void expand(double*);
public:
DVec(); // constructs an empty DVec
void add(double v); //adds v to the end of this DVec
int size();
double pop(); // removes and returns the last value (pre: not-empty)
double get(int idx); // returns value at idx in this DVec
void set(double v, int idx); // sets this DVec at idx to be v
};
Constructor
DVec::DVec()
{
cap = 4;
a = new double[cap];
n = 0;
}
Heres the code that I'm testing it with
void DVec::add(double v)
{
a[n++] = v;
if (n == cap) { expand(a); }
}
void DVec::expand(double*)
{
double* temp = new double[n*2];
for (int i = 0; i < n; i++)
{
temp[i] = a[i];
}
*a = *temp;
}
int main()
{
DVec a; DVec* p = new DVec();
for (int i = 0; i < 6; i++)
{
a.add(i * i);
}
cout << a.get(5);
}
My problem is that it keeps bombing out if I set the for loop to i<6. Anything lower its fine.
It comes back say it threw exception:
if (!has_cctor)
cexit();
My questions is what is this? Is it because I made a pointer equal a pointer(a* = *temp)? Or am I not even in the same galaxy as the correct way to write the function?
Edit:
Thanks for all the help guys. I made changes and it all works now.
{
double* temp = new double[cap++];
for (int i = 0; i < n; i++)
{
temp[i] = a[i];
}
a = temp;
}
DVec::DVec()
{
cap = 0;
a = new double[cap];
n = 0;
}
void DVec::add(double v)
{
if (n >= cap) { expand(a); }
a[n++] = v;
}
This line looks like the problem:
*a = *temp;
I assume you meant to replace a with temp, but what you've written is equivalent to this:
a[0] = temp[0]
You should write this instead:
a = temp;
You also need to remember to delete a before overwriting it, otherwise you will have a memory leak, as well as to update cap, or you will have further problems.
I assume you are doing this as an academic exercise rather than as a solution to a real-world problem. If not, you should use std::vector, as the standard library implementers have already done all the hard work for you.
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;
}
I've tried the (somewhat questionable) convention of deleteing after usage, but that doesn't seem to work. The program is supposed to receive an input of a single integer, sort a randomly created array, and print elapsed time for sorting, yet when I leave the delete in there, the program abnormally ends without even a warning after I do the input. In other words, it crashes. However, when I comment out just the delete line, the program executes perfectly.
The MWE is measuring time for a simple Quick Sort Algorithm, and since this is a school project I cannot change the main() function and using the QuickSort class and its pointers, etc..
The only things I can change are the stuff that goes in the various functions, and although it does seem that set(double*, int) can just be integrated into the constructor, that's not a possible option here for some reason.
The objective is to define a default double* in the constructor, and then delete it and copy input_array into this->arr in set:
EDIT: I use Windows 10 and the GCC C++ Compiler from MinGw-w64. All compilations have been executed in the Windows Command Prompt.
main.cpp
#include <iostream>
#include <cstdlib> // Just for good measure, though this shouldn't be needed
#include "Sort.hpp"
bool check_quick(QuickSort *quick_sort) {
int i = 0;
while(i < (quick_sort->size) - 1) {
if (quick_sort->arr[i] > quick_sort->arr[i + 1]) break;
++i;
} if (i == (quick_sort->size) - 1) return true;
else return false;
}
int main() {
int n; cin >> n;
double *input_array = new double[n];
srand((unsigned int)time(NULL));
for (int k = 0; k < n; k++) input_array[k] = (double)((rand() % n));
QuickSort* quick_sort = new QuickSort();
quick_sort->set(input_array, n);
quick_sort->run();
if (check_quick(quick_sort)) {
cout << "QuickSort is validated" << endl << endl;
} delete quick_sort;
}
Sort.hpp
#define CLOCKS_PER_SECOND 1000
#include <iostream>
#include <ctime>
#include <iomanip> // Use to call setprecision(4)
using namespace std;
class QuickSort {
friend bool check_quick(QuickSort*); // Give access for private variables
public:
void print_time() const {
cout << "QuickSort : " << fixed << setprecision(4) << seconds
<< " sec" << endl;
// << fixed << setprecision(4) always prints to four numbers after point
}
QuickSort() {
this->arr = new double[10];
for (int i = 0; i < 10; ++i) this->arr[i - 1] = i; // Set default array
seconds = clock(); // Set current Millisecond to starting time
}
~QuickSort() {
delete this->arr; // Delete array in object of this class
}
void sorter(double *arr, int begin, int end) { // Sorting Recursive Function
// Size of array without pivot is: end - begin
int pivot = arr[end];
// PIVOT is element at end of subarray "arr[begin...end]"
int i = begin, j = end;
while (i <= j) {
while (arr[i] < pivot) i++; // Increment until arr[i] is larger than
while (arr[j] > pivot) j--; // Decrement until arr[j] is lesser than
if (i <= j) { // If the larger element precedes lesser element
swap(arr[i], arr[j]); // Call Swap function
i++; j--;
} // If i is larger than j now, i was 1 lesser than j before,
// effectively leaving no more elements to scan.
}
if (begin < j) sorter(this->arr, begin, j); // Recursive, larger part
if (end > i) sorter (this->arr, i, end); // Recursive, lesser part
}
void run() {
sorter(this->arr, 0, this->size - 1); // Call Sorter function
seconds = (double)(clock() - seconds) / (double)(CLOCKS_PER_SECOND);
// Calculate Difference of Ticks and divide by Ticks per second.
// Now, `seconds` is passed seconds with millisecond precision.
}
void set(double *arr, int size) {
this->arr = new double[size]; // Make new array of `size` size
for (int i = 0; i < size; i++) this->arr[i] = arr[i]; // Copy input_arr
for (int i = 0; i < size; i++) cout << this->arr[i] << endl; // Copy input_arr
this->size = size; // Save global `size` to object of class
}
void swap(double &p, double &q) { // Swap Function
// Ampersand precedence to change input
double x = p; // Temporary `double` saver
p = q; // p is q
q = x; // q is x, which is p
}
private:
double *arr;
int size;
double seconds;
};
In your QuickSort constructor you are writing outside the bounds of the array that you are allocating:
this->arr = new double[10];
for (int i = 0; i < 10; ++i) this->arr[i - 1] = i; // Set default array
In the first iteration i is 0 so this->arr[i - 1] writes to the element -1. This is only crashing when you call delete as if you don't the runtime doesn't notice this corruption and exits cleanly.
Presumably just changing i-1 to i will produce the desired behaviour.
The first line of QuickSort::set:
this->arr = new double[size]; // Make new array of `size` size
leaks the array allocated in QuickSort's constructor. You need to delete[] that array first, before assigning arr to point to another one:
delete[] arr;
this->arr = new double[size]; // Make new array of `size` size
If this were the real world, and not a shcool assignment, it would be much better not to use a raw pointer in this case. Rather, a std::vector<double> would be much more appropriate.
A quick look reveals that you are using delete instead of delete[]..
this line:
delete this->arr; // Delete array in object of this class
should be:
delete[] this->arr; // Delete array in object of this class
Additionally, as per the convention of delete you should also do this:
delete[] this->arr;
this->arr = nullptr; // This is important, else your are double deleting which is calling for trouble.
I have a problem with the execution of this program. I do not know why it ends up running so abruptly ("The program stopped working"). The results of it are what I hope, however that happens. And I tried many things to avoid it and found that what causes the error is the function void IntArr::addElement(int qtty,int *vec); since if I remove it, the program finishes perfectly and without any error. Analyze the function and for me it's fine, I do not know what is slipping from my hands. The function that what you should do is pass an array with the amount of elements that I want from it and add them to another array.
PS: the original program was well divided by files (class.h, class.cpp, main.cpp), nothing more than to copy them here I had to paste everything together.
I would appreciate your help. Regards!
#include <iostream>
using std::cout;
using std::endl;
#define PRESS_KEY std::cout<<"\nPresione Enter para continuar . . .\n";std::cin.get();
class IntArr{
private:
int * p;
int size;
int used;
//Verificador
void redimensionador(int cant);
public:
//Constructores
IntArr (int sz);
IntArr (int sz,int qtty,int *vec);
//Destructor
~IntArr();
//Visualizadores
void prtArr (void) const;
void prtArr (int cant);
//Accesores
int getSize(){return size;};
int getUsed(){return used;};
//Operaciones
void addElement(int xx);
void addElement(int qtty,int *vec);
};
//Constructores
IntArr::IntArr(int sz){
size = sz;
used = 0;
p = new int[size];
}
IntArr::IntArr(int sz,int qtty,int* vec){
if(qtty>sz){
sz = qtty;
}
size = sz;
used = qtty;
p = new int[size];
p = vec;
}
//Destructor
IntArr::~IntArr(){
delete []p;
}
//Visualizadores
void IntArr::prtArr(void) const{
if(used == 0){
cout<<endl<<"El array no tiene elementos."<<endl;
}
else{
cout<<endl<<"Array: ";
for(int i=0;i<used;i++){
cout<<p[i]<<", ";
}
cout<<endl;
}
}
void IntArr::prtArr(int cant){
if(used == 0){
cout<<endl<<"El array no tiene elementos."<<endl;
}
else{
cout<<endl<<"Array: ";
for(int i=0;i<cant;i++){
cout<<p[i]<<", ";
}
cout<<endl;
}
}
//Operaciones
double IntArr::getAvg(){
double acum = 0;
for(int i=0;i<used;i++){
acum += p[i];
}
return (acum/used);
}
void IntArr::addElement(int xx){
redimensionador(1);
p[used] = xx;
used++;
}
void IntArr::addElement(int qtty,int *vec){
int j=0;
redimensionador(qtty);
for(int i=used;i<(used+qtty);i++){
p[i] = vec[j];
j++;
}
used += qtty;
}
//Verificador
void IntArr::redimensionador(int cant){
if(cant+used>size){
if(cant > 5){
size += cant;
}
else{
size += 5 + cant;
}
}
}
int main(int argc, char *argv[]){
int v_aux[]= {0,5,10,15,20,25,30,35,40};
IntArr A(10,sizeof(v_aux)/sizeof(int),v_aux);
cout<<" size:"<<A.getSize()<<endl<<" used:"<<A.getUsed()<<endl;
A.prtArr();
A.addElement(77);
cout<<" size:"<<A.getSize()<<endl<<" used:"<<A.getUsed()<<endl;
A.prtArr();
A.addElement(11);
cout<<" size:"<<A.getSize()<<endl<<" used:"<<A.getUsed()<<endl;
A.prtArr();
A.addElement(8,v_aux);
cout<<" size:"<<A.getSize()<<endl<<" used:"<<A.getUsed()<<endl;
A.prtArr();
PRESS_KEY;
}
One problem I noticed is in the following lines:
p = new int[size];
p = vec;
When you do that:
You have a memory leak. The value returned by new int[size] is lost to your program.
You point p to the statically defined array in main. That leads to undefined behavior when you use delete [] p; in the destructor.
I am guessing you want to copy the values from vec to p. You'll have to copy the values one by one.
The manually coded version for that:
for (int i = 0; i < used; ++i )
{
p[i] = vec[i];
}
Using the standard library function std::copy:
std::copy(vec, vec+used, p);
If you run out of memory, you can not just say you have more size by adding to an integer. You have to reallocate the memory, copy the values from the old array into the new array, then delete the old array.
You also need to be careful here. Raw pointers are error prone, and I see you have some strange constructs here. For example, IntArr::IntArr(int sz,int qtty,int* vec) you allocate a pointer, then immediately overwrite it. That allocation is a leak.
Be sure you properly update size and used so that you don't lose track of how much memory you actually have. When size changes, so must your buffer or you are out of sync.
Even this constructor has a memory leak and can result in undefined behaviour (for example when vec points to first element of a local array or when the array poined by the argument vec will be deleted).
IntArr::IntArr(int sz,int qtty,int* vec){
if(qtty>sz){
sz = qtty;
}
size = sz;
used = qtty;
p = new int[size];
p = vec;
}
At first a memory is allocated and its address is assigned to p and then p is reassigned.
p = new int[size];
p = vec;
You have to copy elements from the array pointed to by the argument vec into the allocated memory pointed to by the data member p.
And this member function
void IntArr::redimensionador(int cant){
if(cant+used>size){
if(cant > 5){
size += cant;
}
else{
size += 5 + cant;
}
}
}
does not make sense. You have to reallocate the original array pointed to by the data member p.
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.