Dynamic array crashing at constructor - c++

I'm trying to implement a dynamic array of strings for educational purpose. The problem that I ran into is the program crashing whenever I try to add strings to the empty array in my constructor.
Array::Array(string dir, string dim)
{
size = 0;
ptr = new string[size + 1];
ptr[size] = dir;
size++;
ptr[size] = dim;
size++;
}
I have int size and string *ptr declared in my header file. I originally thought this to be a out-of-bounds problem, but after looking at this post, I fixed the initial allocation to size + 1, but the persisting problem seems to prove otherwise.

Changing the value of size does not change the size of the array.
You allocate an array of size 1.
Then you assign something to the first (only) element of that array.
Then you assign something to the second element of that array - but the array only has one element.
Also note that using new does not allocate a dynamic array. Once allocated, the size can't change.

As mentioned by Sid S, "changing the value of size does not change the size of the array."
And for your "inefficient" concern, a common trick that reflect to PaulMcKenzie and Daniel H's idea, is to use the doubling strategy. See the following C code for an simple idea:
#include <stdlib.h>
struct MyArray {
int capacity;
int size;
int *data;
}
/* any other functions you would use, eg: create, destroy of MyArray */
void push(struct MyArray myarray, int n) {
if (size == capacity) {
capacity *= 2;
data = realloc(data, capacity*sizeof(int));
}
/* add the element to the end of data and increase size */
}
In this way, instead of doing realloc every time there is an element added, you would have a lower runtime in average.
A detailed amortized analysis about doubling strategy can be found here.

Instead of string use pointer and allocate memory dynamically every time how much they need not 0 and then ++.
Array :: Array(char *dir,char *dim)
{
int l1,l2;
l1=strlen(dir);
l2=strlen(dim);
/**assume n1 & n2 are data member of "Array" class.**/
n1=new char[l1+1];// allocating memory dynamically
n2=new char[l2+1];
}
I hope it helps.

Related

Shrinking the size of a dynamically allocated array in C++ [duplicate]

I have created an array pointer as a global variable like this:
T *bag;
bag = new T[size];
I have a method where I insert things into the array; however, if it detects that it will overflow the array, I need to resize the array (without vectors). I've been reading about this question all over stack overflow but the answers don't seem to apply to me because I need the data from the old array copied into the new array. Additionally, if I create a new array of a larger size inside the method and then copy the data over to the new array, once the method ends, the array will disappear, but I need it to be a global variable again so all my methods can see it...How should I proceed?
Thank you
Memory, allocated by new, would not disappear after your method ends.
You can return pointer to a new array by usung reference: void f(int *&ptr, size_t &size).
Also, be aware, that you need to clear memory manually arter you use it. For example:
int* newArray = new int[newSize];
... copying from old array ...
int* temp = oldArray;
oldArray = newArray;
delete[] temp;
To resize an array you have to allocate a new array and copy the old elements to the new array, then delete the old array.
T * p_bag;
p_bag = new T[old_size];
//...
T * p_expanded_bag = new T[new_size];
for (unsigned int i = 0; i < old_size; ++i)
{
p_expanded_bag[i] = p_bag[i];
}
delete[] p_bag;
p_bag = p_expanded_bag;
You could use std::copy instead of the for loop.
The thing you need can do the following things
Automatically handle the resizing when requested size is larger than current array size.
When resizing, they can copy the original content to the new space, then drop the old allocation immediately .
There is a non-global-variable way mechanism they can track the array pointer and the current size.
The thing is very similar to std::vector. If it is not allowed to use, you may need manage a dynamic allocated resource like std::vector on your own. You can reference the implementation in that answer link.
If eventually you need to wrap it in a class, make sure to follow the big 3 rules (5 rules in C++11)
You can use realloc from c if you have array of chars/ints/doubles... or some other fundamental data type or classes with only those variables (eg. array of strings won't work).
http://www.cplusplus.com/reference/cstdlib/realloc/
bag = (T*) realloc(bag, new_size * sizeof(T));
Realloc automatically allocate space for your new array (maybe into the same place in memory) and copy all data from given array.
"The content of the memory block is preserved up to the lesser of the new and old sizes, even if the block is moved to a new location."
Example:
#include <stdio.h> /* printf*/
#include <stdlib.h> /* realloc, free */
#include <iostream>
int main()
{
int old_size = 5;
int new_size = 10;
int *array = new int[old_size];
printf("Old array\n");
for (int i=0; i<old_size; i++) {
array[i] = i;
printf("%d ", array[i]);
}
printf("\nArray address: %d\n", array);
array = (int*) realloc(array, new_size * sizeof(int));
printf("New array\n");
for (int i=0; i<new_size; i++)
printf("%d ", array[i]);
printf("\nArray address: %d\n", array);
free(array);
return 0;
}

Copy array then delete original

I have an array of a structure (with the parameters of name and number), and the initial array takes in elements from a document that I've made. The initial list size starts at 1000. When the list fills up, I call another method that I'm struggling with. I would like for it to copy the data into a new array that doubled the size, and then delete the old array.
If I name it: array1 and array2, I have my program use array1 throughout. I need help with the pointers that would get array2 to work as array1.
Is there a way to copy the array to a temp array of the same or new size, and then remake the initial array reassigning back to that? For this exercise, I can't use vectors. While I know how to use them, and that they solve this issue while being better, I'm trying to do it with only arrays.
using namespace std;
struct Information {
char functionality;
int SSN;
string name;
};
int numPeople = 1000;
//Gets called if the initial array (whatever size) is filled
void doubleArray(Information *array){
numPeople = numPeople * 2;
//Will now be the doubled array size
Information temp[numPeople]
for(int i = 0; i < numArray; i++){
temp[i].SSN = array[i].SSN;
temp[i].name = array[i].name;
}
//Normally makes it crash
delete[] array;
}
edit: This is what I currently have
void doubleArray(Information *person){
numPeople = numPeople * 2;
Information* temp = new Information[numPeople];
memcpy(temp, person, numPeople);
delete[] person;
person = temp;
}
It gets to numPeople = 1000 (the initial list size) but then crashes shortly after. Is the doubling array correct?
Arrays are fixed size. You cannot change the capacity of the original array.
{Use std::vector}
You can have a pointer to an array. And use the same pointer. When the array is full, you can allocate another array, copy old array items to new array, delete the old array and assign your array pointer to the new array.
{Did I mention std::vector?}
By the way, there is a data structure that performs resizing as necessary. If I recall correctly, it is std::vector. Try it out. :-)
Assuming you are using std::array (which you should be), then copying the array is very easy.
std::array<myStruct, 1000> array1{};
std::array<myStruct, 2000> array2{};
// codes...
std::copy(array1.begin(), array1.end(), array2.begin())
However, this is a specific scenario in which you only use these two arrays. It will not dynamically double the size of the array as you simply cannot do this dynamically with stack-based arrays, just like c arrays[].
What you can, and should, be using is std::vector<myStruct>. This will dynamically grow as you need it. Until you provide us with code and a more specific issue, this is the best advice that I can offer with the information provided.
If you aren't allowed to use std::vector, as one of your comments stated, then you'll want to look at dynamic allocation.
size_t sz = [whatever];
// Dynamically allocate an array of size sz.
T* T_array = new T[sz];
// Do whatever...
delete[] T_array; // new[] needs to be paired with delete[].
T_array = nullptr; // Not strictly necessary, but a good idea if you have more code after.
As the size doesn't need to be constant for a dynamic array, this will allow you to allocate memory as necessary. You can then use std::copy() to copy data from one array to the other, as Goodies mentioned.
[For more information on dynamic allocation, see here.]

Returning structure array value

So I am writing quite a long code and now I came to a problem. How to change structure's arrray's values and get them back to main function.
What I am trying to do this function is: to insert a new value at first array spot(which is 0). The whole for cycle frees the Z[0] and works fine. But I do not know how to return whole CHANGED structure array to the main program. How to do this?
Thank you.
P.S. sorry, for my broken english.
Here are the neccessary parts of the code:
void insertion(Player Z[], int size); //declaration of the funcion
...
int main()
{
int size=5;
Player *Z = new Player[size];
Insertion(Z, size); //calling the function
...
}
void Insertion(Player Z[], int size) //function
{
size++;
Player* temp = new Player[size];
for(int i=0;i<=size-1;i++)
{
temp[i+1]=Z[i];
}
delete [] Z;
Z = temp;
cin>>Z[0].name;
cin>>Z[0].surname;
}
I see many problems in your code.
For example, why are you allocating an array of 5 Players, then deallocating the array and allocating the array again, having the same size? What's the benefit?
You should also note that C++ has call-by-value semantics so the delete[] Z and Z = temp lines have no effect outside of the function you're calling. So, that function should have a signature void Insertion(Player **Z, int size); or Player *Insertion(Player *Z, int size) if you don't want to modify the argument in-place but instead return the new value.
The comments suggested using std::vector. I heavily recommend that approach. If you need a variable-sized container, std::vector is the best choice.
If you however have a reason to do the manual allocations yourself (such as homework assignment) you should use the following strategy: maintain the size of the array in addition to its capacity, and whenever the size would be greater than the capacity, allocate a new array with twice the capacity, copy the contents and deallocate the old array.

C++ Pointer of Array of Ints Initialization

I want to have an array accessible by all functions of a class.
I put the array as private variable in the header file.
private:
int* arrayName;
In the .cpp file where I implement the class, the constructor takes in an int value (size) and creates the array. The goal is to fill it up
ClassName::ClassName(int numElements){
arrayName = new int[numElements]; //make arrays the size of numElements
for(int i = 0; i<numElements; i++)
arrayName[i] = 0;
}
I feel like this is quite inefficient. I know you can do int array[5] = {0}; but how do you do it when you don't initially know the size.
If you want to zero-initialize a newed array, just do value-initialize it. This has the effect of zero-initializing its elements:
arrayName = new int[numElements]();
// ^^
But you really want to be using an std::vector<int>.
private:
std::vector<int> vname;
and
ClassName::ClassName(int numElements) : vname(numElements) {}
This way you don't have to worry about deleting an array and implementing copy constructors and assignment operators.
You can use the memset function:
memset(arrayName,0,sizeof(int)*numElements);
This void * memset ( void * ptr, int value, size_t num ); function sets the first num bytes of the block of memory pointed by ptr to the specified value (interpreted as an unsigned char).
To use it you must include the string.h header file.
For more information: http://www.cplusplus.com/reference/cstring/memset/
What you want to do is progressively expand the array on demand.
arrayName = new int[numElements];
for(int i = 0; i<numElements; i++)
arrayName[i] = 0;
The above code (what you gave) will give you an array of size numElements, and THEN the for loop will fill it. This is allocated now, and can't, as I understand it, be simply or easily resized (memset will overwrite previously held values in the array).
You could copy the whole array over every time you want to resize it:
int * oldarr = new int[OldSize];
//fill your old array
int * newarr = new int[NewSize];
for(int i = 0; i<OldSize; i++)
newarr[i] = oldarr[i];
Other than that, you could make the array much larger, or you could use various STLs, such as std::vector. Vector can be increased with a simple push_back function, and allows [] operator access (like arr[5] and whatnot).
Hope this helps!

Arrays and pointers in a template

I am attempting to write a template/class that has a few functions, but I'm running into what seems like a rather newbie problem. I have a simple insert function and a display values function, however whenever I attempt to display the value, I always receive what looks like a memory address(but I have no idea), but I would like to receive the value stored (in this particular example, the int 2). I'm not sure how to dereference that to a value, or if I'm just completely messing up. I know that vectors are a better alternative, however I need to use an array in this implementation - and honestly I would like to gain a more thorough understanding of the code and what's going on. Any help as to how to accomplish this task would be greatly appreciated.
Example Output (running the program in the same way every time):
003358C0
001A58C0
007158C0
Code:
#include <iostream>
using namespace std;
template <typename Comparable>
class Collection
{
public: Collection() {
currentSize = 0;
count = 0;
}
Comparable * values;
int currentSize; // internal counter for the number of elements stored
void insert(Comparable value) {
currentSize++;
// temparray below is used as a way to increase the size of the
// values array each time the insert function is called
Comparable * temparray = new Comparable[currentSize];
memcpy(temparray,values,sizeof values);
// Not sure if the commented section below is necessary,
// but either way it doesn't run the way I intended
temparray[currentSize/* * (sizeof Comparable) */] = value;
values = temparray;
}
void displayValues() {
for (int i = 0; i < currentSize; i++) {
cout << values[i] << endl;
}
}
};
int main()
{
Collection<int> test;
int inserter = 2;
test.insert(inserter);
test.displayValues();
cin.get();
return 0;
}
Well, if you insist, you can write and debug your own limited version of std::vector.
First, don't memcpy from an uninitialized pointer. Set values to new Comparable[0] in the constructor.
Second, memcpy the right number of bytes: (currentSize-1)*sizeof(Comparable).
Third, don't memcpy at all. That assumes that Comparable types can all be copied byte-by-byte, which is a severe limitation in C++. Instead:
EDIT: changed uninitialized_copy to copy:
std::copy(values, values + currentSize - 1, temparray);
Fourth, delete the old array when it's no longer in use:
delete [] values;
Fifth, unless the code is going to make very few insertions, expand the array by more than one. std::vector typically increases its size by a factor of 1.5.
Sixth, don't increment currentSize until the size changes. That will change all those currentSize-1s into currentSize, which is much less annoying. <g>
Seventh, an array of size N has indices from 0 to N-1, so the top element of the new array is at currentSize - 1, not currentSize.
Eighth, did I mention, you really should use std::vector.
This line is wrong:
memcpy(temparray,values,sizeof values);
The first time this line is run, the values pointer is uninitialized, so it will cause undefined behavior. Additionally, using sizeof values is wrong since that will always give the size of a pointer.
Another issue:
temparray[currentSize] = value;
This will also cause undefined bahavior because you have only allocated currentSize items in temparray, so you can only access indices 0 to currentSize-1.
There is also an error in your array access.
temparray[currentSize/* * (sizeof Comparable) */] = value;
Remember that arrays start at index zero. So for an array of length 1, you would set temparray[0] = value. Since you increment currentSize at the top of the insert function, you will need to do this instead:
temparray[currentSize-1] = value;