Dynamically Growing an Array in C++ - c++

I have an array of pointers of CName objects. I have the following constructor which initializes my array to size one. Then when I add an object I grow the array by 1 and add the new object. It compiles fine, however when I try to print them I just get segmentation fault error. Can you look and see if I'm doing anything wrong?
//constructor
Names_Book::Names_Book()
{
grow_factor = 1;
size = 0;
cNames = (CName**)malloc(grow_factor * sizeof(CName*));
cNames[0] = NULL;
}
void Names_Book::addCName(CName* cn)
{
int oldSize = size;
int newSize = size + 1;
CName** newCNames = (CName**)malloc(newSize * sizeof(CName*));
for(int i=0; i<newSize; i++)
{
newCNames[i] = cNames[i];
}
for(int i=oldSize; i<newSize; i++)
{
newCNames[i] = NULL;
}
/* copy current array to old array */
cNames = newCNames;
delete(newCNames);
size++;
}

To have dynamically growable array in C++, you should use std::vector or at least look at its implementation.

There are a few things wrong with this function:
void Names_Book::addCName(CName* cn)
{
int oldSize = size;
int newSize = size + 1;
CName** newCNames = (CName**)malloc(newSize * sizeof(CName*));
for(int i=0; i<newSize; i++)
{
newCNames[i] = cNames[
}
for(int i=oldSize; i<newSize; i++)
{
newCNames[i] = NULL;
}
/* copy current array to old array */
cNames = newCNames; //right here you just leaked the memory cNames was pointing to.
delete(newCNames); // right here you delete the new array you just created using the wrong call.
size++;
}
Near the end you do two things quite wrong. (Commented above.)
Those last two lines should be:
free(cNames);
cNmaes = newCNames;
Also, you should do a realloc rather than slowly copying elements one by one....
With that said, you should use vector.
Don't try to (poorly) rewrite what already exists.

The first loop should be to oldSize:
for(int i=0; i<oldSize; i++)
cNames isn't big enough for newSize.

Related

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 do I stop my resize function from causing _BLOCK_TYPE_IS_VALID(pHead -> nBlockUse)?

I've been tasked with implementing a stack using arrays However, when I run the program it says _BLOCK_TYPE_IS_VALID(pHead -> nBlockUse). The debugger directed me to the delete statement in the resize function, but I'm unsure how to fix the problem.
Note: I'm trying to do so without using vectors.
void resize(){
Type* temp = new Type[asz + 2]; // store old values
for (int i = 0; i < asz; ++i){ temp[i] = arr[i]; }
delete[asz] arr; // delete old array
arr = temp; // keep new larger arr
delete[] temp;
asz =+2; // array size
}
Here's a couple of changes that may fix your problem. You don't initialise sz, your final for-loop was copying according to the new increased size, yet tempwas only the old size. You also don't appear to set the new sz anywhere. Could be any or all of these that cause a memory overwrite invalidating the debug blocks and causing the assertion you have seen.
void resize(Type& arg){
Type* temp = new Type[arg.sz]; // store old values
for (int i = 0; i < arg.sz; ++i){ temp[i] = arg[i]; }
int oldSz = arg.sz, newSz=arg.sz + 2;
delete[] arg; // delete old array
arg = new Type[newSz]; // create new larger arr
arg.sz = newSz;
for (int i = 0; i < oldSz; ++i){ arg[i] = temp[i]; } //copy back
delete[] temp;
}

How to create an array of pointers inside a function whose size is not known till run time

In main I can:
Node* myNodeArray2[myHeight][myWidth];//Does not call constructor
for(int i=0; i<myHeight; i++){
for(int j=0; j<myWidth; j++){
theNodeArray[i][j] = new Node("ThisIsTest", 5, 5);
}
}
So for the above code myHeight and myWidth can be user input at run time. It does not call the default constructor and I can use the new operator and go through the array creating the objects.
I want to be able to pass Node* myNodeArray2 to a function and let it create the array size and populate it. When it is created I want the elements to be pointers. I don't want to call the default constructor. I want to be able to at my choosing call the new operator with the non-default constructor.
When I try:
void Test(Node*& theNodeArray, int myHeight, int myWidth){
theNodeArray = new Node*[myHeight][myWidth];
}
int main(){
Node* myNodeArray;
Test(myNodeArray, myHeight, myWidth);
}
I get that
"myWidth is not a constant expression."
I have tried a couple of different methods but cannot get what I want. I need the creation to happen in a separate function. I need to be able to define the size at runtime. Any help?
Edit:
I don't want to use std::vector.
Edit 2:
I don't want to do this
int** ary = new int*[sizeX];
for(int i = 0; i < sizeX; ++i)
ary[i] = new int[sizeY];
As this forces the rows to be of objects of contiguous memory space. I want to allocate a 2d array of pointers. I do not want to necessarily create the objects that will be pointed to.
You may use the following:
Node*** MakeArrayNodePtr(int myHeight, int myWidth){
Node*** res = new Node**[myHeight];
for (int i = 0; i != myHeight; ++i) {
res[i] = new Node*[myWidth]();
}
return res;
}
And don't forget
void DeleteArrayNodePtr(Node*** nodes, int myHeight, int myWidth)
{
for (int i = 0; i != myHeight; ++i) {
// And probably:
/*
for (int j = 0; j != myWidth; ++j) {
delete nodes[i][j];
}
*/
delete [] nodes[i];
}
delete [] nodes;
}

declare and delete this version of a 2D array in c++

int *array[10];
for(int i = 0; i < 10; i++)
array[i] = new int[10];
//...
void passFunc(int *a[10]) //array containing pointers
{
//...
}
passFunc(array);
Im trying to figure out how to declare and delete this version of a 2D array. I started using int ** array, but in order to make one section of code easier, I need to switch to *[]. Can anyone help me out?
I have tried compiling my actual code (the above code is just an example), which looks like this:
int* filedata[LENGTH] = new int*[LENGTH]; //ERROR: array must be initialized with brace- enclosed identifiers.
EDIT:
Thanks!
Something like that
int** array = new int*[sizeX];
for(int i = 0; i < sizeX; ++i)
array[i] = new int[sizeY];
To delete
for(int i = 0; i < sizeX; ++i)
delete [] array[i];
delete [] array;
If I have understood correctly what you want then the allocation and deallocation will look as
int ** filedata = new int * [LENGTH];
for ( int i = 0; i < LENGTH; i++ ) filedata[i] = new int [LENGTH];
//...
for ( int i = 0; i < LENGTH; i++ ) delete [] filedata[i];
delete [] filedata;
Alternate version to the ones given:
int** array = new int*[sizeX];
int *pool = new int[sizeX * sizeY];
for(int i = 0; i < sizeX; ++i, pool += sizeY)
array[i] = pool;
To delete:
delete [] array[0];
delete [] array;
The advantage of using this is:
Only two calls to new[] and delete[] are required, regardless of the number of columns. In the previous answer, the number of calls to new and delete depend on the number of columns. This reduces fragmentation, and also will probably give you a speed increase if the number of columns is very large.
The data is contiguous. You can access any element in the 2d array from any other element using a simple offset.
The disadvantage is that the number of columns for each row needs to be the same, otherwise it becomes very difficult to maintain.

c++ deallocate 2d int array error

I get very frustrating error in following piece of code. Thats my array.
int **tab2 = new int*[3];
I allocate this like it.
for(i = 0; i < 10; i++) {
tab2[i] = new int[3];
tab2[i][0] = 40;
tab2[i][1] = 10;
tab2[i][2] = 100;
}
Then after using it i want to destroy it.
for(i = 0; i < 10; i++) {
delete [] tab2[i];
}
delete [] tab2;
And this causes core dump every single time. I tried many different ways to destroy it and every time get this error. What im making wrong here ?
This
int **tab2 = new int*[3];
does not do what you think it does.
You want an array that will contain TEN (10) pointers, each to an array of THREE ints.
new int*[3] is an array that contain THREE pointers.
What you want is this (live at coliru):
#include <iostream>
int main() {
int **tab2 = new int*[10];
for(int i = 0; i < 10; i++) {
tab2[i] = new int[3];
tab2[i][0] = 40;
tab2[i][1] = 10;
tab2[i][2] = 100;
}
for(int i = 0; i < 10; i++) {
delete [] tab2[i];
}
delete [] tab2;
}
With
int **tab2 = new int*[3];
you allocate an array of pointers of size 3. But than with
for(i = 0; i < 10; i++) {
tab2[i] = new int[3];
//...
}
you access it with up to index 9. That will surely go wrong.
The deletion process looks fine to me. To fix it, you should allocate an array of pointers with size 10instead of 3, e.g.
int **tab2 = new int*[10];
Looks like what you're trying to do is to create an N by M array, where N is known at runtime and M is fixed (in this case, 3).
Why not just do this?
{
std::array<int, 3> defaults = {{ 40, 10, 100 }};
std::vector<std::array<int, 3>> thing(10, defaults);
}
The vector, thing is automatically deallocated when it goes out of scope, and its size can be set at runtime. You still access the structure in the same way:
thing[1][2] = 3
Manual memory management can be easily avoided by using standard containers and smart pointers. Doing so will keep you code cleaner, and have fewer opportunities for dangling pointers and memory leaks.