Dynamically allocating memory for changing array size starting with unknown size C++ - c++

How do I dynamically allocate an array where the size will be changing because the stuff stored in the array will be read from a file. There are lots of suggestions on using a vector, but I want to know how to do it the array way.
I know for memory allocation it is
int count;
int *n = new int[count];
Say the variable count is going to increment in a loop. How would I change the size of the array?
Also, what if we did it using malloc?

Don't try to make the array allocation exactly follow the continual changing size requirements of what you are going to store. Consider using the traditional 2*N multiple. When array is full, reallocate by growing by 2*N (allocate a new array twice as large), and copy items over. This amortizes the reallocation cost logarithmically.
Keep in mind that this logic you are setting out to implement with low level arrays is exactly why vector exists. You are not likely to implement your own as efficiently, or as bug free.
But if you are set on it, keep count a multiple of 2, starting with something realistic (or the nearest multiple of 2 rounded up)

You may keep two pointers, p and q(placeholder), when count changes, you need to do a fresh allocation for p, before that earlier allocations need to be deallocated, even before that the contents of earlier p should be transferred to new p as well.
int count, oldcount;
int *p = NULL;
int *q;
p = new int[count];
oldcount = count;
when you need to re-allocate:
q = new int[count];
memcpy(q, p, oldcount * sizeof(int)); // OR for (int i = 0; i < oldcount; i++) q[i] = p[i];
delete [] p;
p = q;
oldcount = count; // for use later
If you use malloc, calloc then you need to use as number of bytes to pass in malloc. but not needed with new and delete operators in C++

How would I change the size of the array?
Using new: You can't. The size of an object (here, an array object) can't change at runtime.
You would have to create a new array with the appropriate size, copy all elements from the old into the new array and destroy the old one.
To avoid many reallocations you should always allocate more than you need. Keep track of the size (the amount of elements currently in use) and the capacity (the actual size of the allocated array). Once you want to increase the size, check whether there is still some memory left (size<capacity) and use that if possible; otherwise, apply the aforementioned method.
And that's exactly what vector does for you: But with RAII and all the convenience possible.

Related

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.]

Allocate more memory for dynamically allocated array

My C++ algorithm obtains data with unknown size (it detects particles on the image one by one, and I cannot know how many particles will be detected before this algorithm finishes its work).
So, first I want to allocate, say, array with 10000 elements, and during the processing, if necessary, allocate another 10000 elements several times.
Here is what I tried, it doesn't work:
#include <iostream>
using namespace std;
int main(){
int n = 3;
int m = 3;
float *a = new float[3];
a[0] = 0;
a[1] = 1;
a[2] = 2;
float *b = a + 2;
b = new float[3];
b[0] = 4;
b[1] = 5;
cout << a[3] << endl;
}
As a result, I got minus infinity. Of course, I can handle this in different arrays, I can allocate a huge amount of memory once. I need to pass full array of detected data to the function after, so, as a result, I want to have one big array.
But still, is there a way to increase the size of your dynamically allocated way? What I want in a toy example is to increase number of elements in array a by 3, so it will have 6 elements.
In Matlab it is absolutely possible. What about C++?
Thanks
You should just use std::vector instead of raw arrays. It is implemented to grow efficiently. You can change its size with resize, append to it with push_back or insert a range (or various other things) with insert to grow it.
Changing the size of a manually allocated array is not possible in C++. Using std::vector over raw arrays is a good idea in general, even if the size does not change. Some arguments are the automated, leak-proof memory management, the additional exception safety as well as the vector knowing its own size.
No, you can't increase the size of an array. If you want to use an array, you'll have to allocate a new block, large enough for the whole new array, and copy the existing elements across before deleting the old array. Or you could use a more complicated data structure that doesn't store its elements contiguously.
Luckily, the standard library has containers to handle this automatically; including vector, a resizable array.
std::vector<float> a(3);
a[0] = 0;
a[1] = 1;
a[2] = 2;
// you can resize it by specifying a new size
a.resize(4);
a[3] = 3;
// or by appending new elements
a.push_back(4);
You should use a vector and then resize when necessary or let it grow by itself.
When you do:
float *b = a + 2;
b = new float[3];
the memory allocated will not be allocated contiguously to the first allocation even if you previously set the pointer to point at the end(it will be overwritten anyway). Therefore, when accessing a[3], you get out of bound.

When allocating a dynamic array, are the previous elements deleted?

Title says it all more or less. When I need an (for the sake of this example) integer array for an unknown amount of values I know I can change it's size using new *array = new int[size]. Now my question is: If I have an array of a certain size, but I need to make it bigger, can I just use the new operator to expand it and will it still have all previously stored elements or would it be smarter to create a whole new array with a dynamic size, copy all elements from the previous array into the new one and delete[] the old array. Basically just swapping between the two arrays, whenever I need a new size.
Specifically I am asking whether or not this piece of code would work in the way it's intended to work
for(int i = 1; i < 10; i++){
int *array = new int[i];
array[i-1] = i;
}
My assumption is that this array will first be the size of 1 and store the value 1 at index 0. Then it will reallocate its size to 2 and store the value to at index 1 and so on until i is 9.
I guess to rephrase my question a bit better: Does an array initialized with new have to be populated with elements or will it copy the elements it had from before using the operator?
You can't resize the array in this way. You need to make a new array and then copy the old array into it. You can also try std::vector, which does what you want automatically.
If you want to use pointers rather than std::vector to change the size of your array, you can do it in this way.
int n = 100; // This will be the number of elements.
int *array1; // Pointer
array1 = new int[n]; // This will allocate your array with size n, so you will have 100 elements. You can combine this with the previous in int *array1 = new int[n];
So fill up the this array however you please...
Then you decide you want a 200 element array instead? You will need to create a different array in the same way.
int *array2 = new int[200];
You can use the for loop to copy array 1 into array 2. The for loop should iterate as many times as there are elements in array 1 (100).
for(int i = 0; i < 100; ++i)
array2[i] = array[1];
At this stage array2 is exactly the same as array1, but with 100 uninitialized elements at your disposal from [100] to [199].
You won't need array1 anymore, so at some point, you should call
delete [] array1;
Your assumption, by the way would not work, because on the first cycle of your loop, you create (or try to create) an array of i=1 element. Arrays start counting at 0, so your only single element is [0]. When i is at 0, what is i-1?
If you try to access array[-1], you'll probably crash. But why should you want to create 10 different arrays? new keyword creates an unrelated object, not overwrites the one with the same name.
Does an array initialized with new have to be populated with elements or will it copy the elements it had from before using the operator?
new[] allocates new array, completely independent from previous.
I know 3 ways to "make the array bigger":
As #ravi mentioned, don't mess with poinsters, use modern std::vector.
Make new array in new pointer, std::move elements from old array to the new one, and then delete[] old array.
Get rid of new[] & delete[], use old realloc with malloc & free.
You have to allocate new array and copy old array's data into that. This is how vector is implemented. Had there been better way of doing it, C++ standard community would have considered that.

Why can't initial length be 1 in a dynamically-allocated array?

Let's say we start out with:
int *newArray = new int[1];
And then later have something like:
ifstream inputFile("File.txt");
Counter=0;
while (inputFile >> newValue)
{
newArray[Counter] = newValue;
Counter++
}
If I try to pull 100 lines from the text file, the program will eventually crash. However, if I had used
int *newArray = new int[100];
originally, it doesn't crash.
If it's dynamically allocating memory, why does it need an initial value more than 1? That makes no sense to me. Having to define any initial length beyond a small number such as 1 or 10 defeats the whole purpose of dynamic memory allocation...
EDIT: This is for school, we aren't allowed to use vectors yet.
The language will not "dynamically allocate memory" for you. It is your responsibility to allocate and reallocate your arrays so that their sizes are sufficient for your purposes.
The concept of "dynamic allocation" in C++ never meant that memory will somehow allocate itself automatically for you. The word "dynamic" in this context simply means that the parameters and lifetime of the new object are determined at run time (as opposed to compile time). The primary purpose of dynamic memory allocation is: 1) to manually control object's lifetime, 2) to specify array sizes at run-time, 3) to specify object types at run-time.
The second point is what allows you to do this
int n = ...; // <- some run-time value
int *array = new int[n];
which is not possible with non-dynamically allocated arrays.
In your example, you can allocate an array if size 1 initially. Ther's nothing wrong with it. But it is still your responsibility to allocate a new, bigger array, copy the data to the new array and free the old one once you need more space in your array.
In order to avoid all that hassle you should simply use a library-provided resizable container, like std::vector.
It's not dynamic in the sense that it can dynamically resize itself. It's dynamic in the sense that its size can be chosen dynamically at runtime, instead of compile time. One of the primary philosophies of C++ is that you don't pay for what you don't use. If dynamic arrays worked the way you are asking, that would require bounds checking, something I don't need, so I don't want to pay for it.
Anyway, the problem is solved with the standard library.
std::vector<int> vec;
...
while (inputFile >> newValue)
{
vec.push_back(newValue);
}
Isn't that much nicer? You don't even have to keep track of the size, because vector keeps track of it for you.
If you can't use vector, then you've got a lot of work ahead of you. The principle is essentially this. You keep 2 additional integer variables. One to indicate the number of values you are using in your array, and one to indicate the current capacity of your array. When you run out of room, you allocate more space. For example, here is a poor man's non-exception safe version of a vector:
int size = 0;
int capacity = 1;
int array = new int[capacity];
while (inputFile >> newValue)
{
if (size == capacity)
{
capacity *= 2;
int * newArray = new int[capacity];
for (int i=0; i<size; ++i)
newArray[i] = array[i];
delete [] array;
array = newArray;
}
array[size++] = newValue;
}
You're only creating space for one int but trying to store several, of course it crashes. Even if you created it with size 100 it'd still crash when you tried to save the 101'th value.
If you need an automatically resizing container check out std::vector.
#include <vector>
std::vector<int> data;
while (inputFile >> newValue)
{
data.push_back(newValue);
}
This will work until your process runs out of memory.

How to expand an array dynamically in C++? {like in vector }

Lets say, i have
int *p;
p = new int[5];
for(int i=0;i<5;i++)
*(p+i)=i;
Now I want to add a 6th element to the array. How do I do it?
You have to reallocate the array and copy the data:
int *p;
p = new int[5];
for(int i=0;i<5;i++)
*(p+i)=i;
// realloc
int* temp = new int[6];
std::copy(p, p + 5, temp); // Suggested by comments from Nick and Bojan
delete [] p;
p = temp;
You cannot. You must use a dynamic container, such as an STL vector, for this. Or else you can make another array that is larger, and then copy the data from your first array into it.
The reason is that an array represents a contiguous region in memory. For your example above, let us say that p points to address 0x1000, and the the five ints correspond to twenty bytes, so the array ends at the boundary of 0x1014. The compiler is free to place other variables in the memory starting at 0x1014; for example, int i might occupy 0x1014..0x1018. If you then extended the array so that it occupied four more bytes, what would happen?
If you allocate the initial buffer using malloc you can use realloc to resize the buffer. You shouldn't use realloc to resize a new-ed buffer.
int * array = (int*)malloc(sizeof(int) * arrayLength);
array = (int*)realloc(array, sizeof(int) * newLength);
However, this is a C-ish way to do things. You should consider using vector.
Why don't you look in the sources how vector does that? You can see the implementation of this mechanism right in the folder your C++ include files reside!
Here's what it does on gcc 4.3.2:
Allocate a new contiguous chunk of memory with use of the vector's allocator (you remember that vector is vector<Type, Allocator = new_allocator>?). The default allocator calls operator new() (not just new!) to allocate this chunk, letting himself thereby not to mess with new[]/delete[] stuff;
Copy the contents of the existing array to the newly allocated one;
Dispose previously aligned chunk with the allocator; the default one uses operator delete().
(Note, that if you're going to write your own vector, your size should increase "M times", not "by fixed amount". This will let you achieve amortized constant time. For example, if, upon each excession of the size limit, your vector grows twice, each element will be copied on average once.)
Same as others are saying, but if you're resizing the array often, one strategy is to resize the array each time by doubling the size. There's an expense to constantly creating new and destroying old, so the doubling theory tries to mitigate this problem by ensuring that there's sufficient room for future elements as well.