Expanding a dynamically allocated array - c++

I have allocated an array as follows.
#include <iostream>
int main() {
const int first_dim = 3;
const int second_dim = 2;
// Allocate array and populate with dummy data
int** myArray = new int*[first_dim];
for (int i = 0; i < first_dim; i++) {
myArray[i] = new int[second_dim];
for (int j = 0; j < second_dim; j++) {
myArray[i][j] = i*second_dim + j;
std::cout << "[i = " << i << ", j = " << j << "] Value: " << myArray[i][j] << "\n";
}
}
// De-allocate array
for (int i = 0; i < first_dim; i++)
delete[] myArray[i];
delete[] myArray;
}
Let's say I want to add a 4th element to the first dimension, i.e. myArray[3]. Is this possible?
I've heard that Vectors are so much more efficient for this purpose, but I hardly know what they are and I've never used them before.

Yes, but in a very painful way. What you have to do is allocate new memory which now has your new desired dimensions, in this case 4 and 2, then copy all the contents of your matrix to your new matrix, and then free the memory of the previous matrix... that's painful. Now let's see how the same is done with vectors:
#include <vector>
using std::vector;
int main()
{
vector< vector <int> > matrix;
matrix.resize(3);
for(int i = 0; i < 3; ++i)
matrix[i].resize(2);
matrix[0][1] = 4;
//...
//now you want to make the first dimension 4? Piece of cake
matrix.resize(4);
matrix[3].resize(2);
}
HTH
edit:
some comments on your original code:
In C++ ALL_CAP_NAMES usually refer to macros (something you #define). Avoid using them in other contexts
why do you declare FIRSTDIM and SECONDDIM static? That is absolutely unnecessary. If a local variable is static it means informally that it will be the same variable next time you call the function with kept value. Since you technically can't call main a second sime this is useless. Even if you could do that it would still be useless.
you should wrire delete [] array[i]; and delete [] array; so the compiler knows that the int* and int** you're trying to delete actually point to an array, not just an int or int* respectively.

Let's say I want to add a 4th element to the first dimension, i.e. myArray[3]. Is this possible?
Yes, but it's a pain in the neck. It basically boils down to allocating a new array, just as your existing code does (hint: put it in the function and make the sizes arguments to that function) and copying compatible elements over.
Edit: One of the things that std::vector does for you is properly de-allocating you memory. In the code you have, failure to allocate one of the arrays along the 2nd dimension will result in a memory leak. A more robust solution would initialize pointers to 0 before performing any allocation. An exception block could then catch the exception and free whatever was partially allocated.
Because this code becomes complex quickly, people resort to allocating a single buffer and addressing using a stride or using a 1D array of 1D arrrays (i.e. std::vector of std::vectors).

Related

Why use a dynamic array instead of a regular array?

The following code is used to demonstrate how to insert a new value in a dynamic array:
#include <iostream>
int main()
{
int* items = new int[5] {1, 2, 3, 4, 5}; // I have 5 items
for (int i = 0; i < 5; i++)
std::cout << items[i] << std::endl;
// oh, I found a new item. I'm going to add it to my collection.
// I do this by
// (1) allocating a bigger dynamic array
// (2) copying the existing elements from the old array to the new array
// (3) deleting the old array, redirecting its pointer to the new array
int* items_temp = new int[6];
for (int i = 0; i < 5; i++)
items_temp[i] = items[i];
items_temp[5] = 42;
delete[] items;
items = items_temp;
for (int i = 0; i < 6; i++)
std::cout << items[i] << std::endl;
delete[] items;
}
I am confused about the necessity of using it over a regular array. Can't I just do the same thing with a regular array? Basically, you just define a new array with a larger size and move elements in the previous array to this new array. Why is it better to use a dynamic array here?
You are right, the example you are looking at isn't very good at demonstrating the need for dynamic arrays, but what if instead of going from size 5->6, we had no idea how many items we found until we need to add until the code is actually running?
Regular arrays need to be constructed with their size known at compile time
int foo [5] = { 16, 2, 77, 40, 12071 };
But dynamic arrays can be be assigned as size at runtime
int* Arrary(int size) {
return new int[size];
}
So if you don't know the size of your array, or it may need to grow/shrink you need to use a dynamic array (or better yet just use a std::vector).
Suppose you want to do what you mentioned a multiple times.
for(int i = 0; i < some_val; ++i)
{
int val_to_add;
std::cin >> val_to_add;
int* new_arr = new int[old_size + 1]; // the value is suppsoed to be big in order to indicate that it takes much memory.
copy_old_to_new(new_arr, old_arr); //some function which does the copying.
new_arr[old_size + 1] = val_to_add;
delete[] old_arr;
old_arr = new_arr;
}
Now think about what would happen if we tried to do the same with static arrays.
We wouldn't be able to remove the memory allocated by the old_arr, and the program would use a lot of memory.
We wouldn't be able to construct an array which would be accessible outside the loop, which, obviously, is not intended.
In your example it is not much clear how the usage of dynamic arrays would make use in your intention. So if you feel you could do the same without dynamic arrays, do it without them.

Dynamic resizing array code not working in C++?

I am trying to create an array, which doubles every time it is completely filled.
#include <iostream>
using namespace std;
int* array_doubler(int* array, int size){
int *new_array = new int[size*2];
for(int i = 0; i < size; i++){
new_array[i] = array[i];
}
delete[] array;
return new_array;
}
int main()
{
int N = 10; // Size of array to be created
int *array = new int[0];
for(int i = 0; i < N; i++)
{
if(array[i] == '\0')
array = array_doubler(array, i);
array[i] = i*2;
}
//Printing array elemensts
for(int i = 0; i < N; i++)
cout << array[i] << '\t';
cout << '\n';
return 0;
}
Problem is when I create dynamic memory with new, all the spots have the null character \0 value in them (not just the last spot). i.e. If i write:
int* p = new int[5];
then all the 5 blocks in memory p[0],p[1],p[2],p[3],p[4],p[5] have \0 in them, not just the p[5]. So the if(array[i] == '\0') in my main() calls array_doubler for every single iteration of for loop. I want it to fill the available spots in the array first and when it reaches the last element, then call array_doubler.
Problem is when I create dynamic memory with new, all the spots have the null character \0 value in them (not just the last spot).
Actually they have undefined values in them. 0 is a valid value for them to have, but tomorrow the compiler might suddenly decide that they should all have 1 instead of 0.
If you want to detect the end of an array, then you have to remember how big the array is. C++ doesn't do it for you. Actually, it does do it for you if you use std::vector, but I suppose that's not the point of this exercise.
I'm not sure why you'd want to do this, as std::vector offer this kind of feature, and are more idiomatic of c++ (see isocpp faq on why C-style array are evil).
One of the issue of C-style array is the fact that they donĀ“t know their own size, and that they don't have default value, thus stay uninitialized.
If for some reason you need to not use std::vector, the next best solution would be to wrap the array with it's size in a structure or a class (which is kinda what std::vector is doing), or to initialize your array using std::memset (which is the C function you would use if you were in C).
Do keep in mind that this is not considered as good practices, and that the STL offer plenty of solution when you need containers.

Dynamically allocating memory

I am new to C++ and programming in general so i apologize if this is a trivial question.I am trying to initialize 2 arrays of size [600][600] and type str but my program keeps crashing.I think this is because these 2 arrays exceed the memory limits of the stack.Also,N is given by user so i am not quite sure if i can use new here because it is not a constant expression.
My code:
#include<iostream>
using namespace std;
struct str {
int x;
int y;
int z;
};
int main(){
cin>>N;
str Array1[N][N]; //N can be up to 200
str Array2[N][N];
};
How could i initialize them in heap?I know that for a 1-D array i can use a vector but i don't know if this can somehow be applied to a 2-D array.
How 2-or-more-dimensional arrays work in C++
A 1D array is simple to implement and dereference. Assuming the array name is arr, it only requires one dereference to get access to an element.
Arrays with 2 or more dimensions, whether dynamic or stack-based, require more steps to create and access. To draw an analogy between a matrix and this, if arr is a 2D array and you want access to a specific element, let's say arr[row][col], there are actually 2 dereferences in this step. The first one, arr[row], gives you access to the row-th row of col elements. The second and final one, arr[row][col] reaches the exact element that you need.
Because arr[row][col] requires 2 dereferences for one to gain access, arr is no longer a pointer, but a pointer to pointer. With regards to the above, the first dereference gives you a pointer to a specific row (a 1D array), while the second dereference gives the actual element.
Thus, dynamic 2D arrays require you to have a pointer to pointer.
To allocate a dynamic 2D array with size given at runtime
First, you need to create an array of pointers to pointers to your data type of choice. Since yours is string, one way of doing it is:
std::cin >> N;
std::string **matrix = new string*[N];
You have allocated an array of row pointers. The final step is to loop through all the elements and allocate the columns themselves:
for (int index = 0; index < N; ++index) {
matrix[index] = new string[N];
}
Now you can dereference it just like you would a normal 2D grid:
// assuming you have stored data in the grid
for (int row = 0; row < N; ++row) {
for (int col = 0; col < N; ++col) {
std::cout << matrix[row][col] << std::endl;
}
}
One thing to note: dynamic arrays are more computationally-expensive than their regular, stack-based counterparts. If possible, opt to use STL containers instead, like std::vector.
Edit: To free the matrix, you go "backwards":
// free all the columns
for (int col = 0; col < N; ++col) {
delete [] matrix[col];
}
// free the list of rows
delete [] matrix;
When wanting to allocate a 2D array in C++ using the new operator, you must declare a (*pointer-to-array)[N] and then allocate with new type [N][N];
For example, you can declare and allocate for your Array1 as follows:
#define N 200
struct str {
int x, y, z;
};
int main (void) {
str (*Array1)[N] = new str[N][N]; /* allocate */
/* use Array1 as 2D array */
delete [] Array1; /* free memory */
}
However, ideally, you would want to let the C++ containers library type vector handle the memory management for your. For instance you can:
#include<vector>
..
std::vector <std::vector <str>> Array1;
Then to fill Array1, fill a temporary std::vector<str> tmp; for each row (1D array) of str and then Array1.push_back(tmp); to add the filled tmp vector to your Array1. Your access can still be 2D indexing (e.g. Array1[a][b].x, Array1[a][b].y, ..., but you benefit from auto-memory management provided by the container. Much more robust and less error prone than handling the memory yourself.
Normally, you can initialize memory in heap by using 'new' operator.
Hope this can help you:
// Example program
#include <iostream>
struct str {
int x;
int y;
int z;
};
int main()
{
int N;
std::cin>>N;
str **Array1 = new str*[N]; //N can be up to 200
for (int i = 0; i < N; ++i) {
Array1[i] = new str[N];
}
// set value
for (int row = 0; row < N; ++row) {
for (int col = 0; col < N; ++col) {
Array1[row][col].x=10;
Array1[row][col].y=10;
Array1[row][col].z=10;
}
}
// get value
for (int row = 0; row < N; ++row) {
for (int col = 0; col < N; ++col) {
std::cout << Array1[row][col].x << std::endl;
std::cout << Array1[row][col].y << std::endl;
std::cout << Array1[row][col].z << std::endl;
}
}
}

dynamically allocate an Array

I want to declare a 2D Array without an initial size. It keeps on giving me an error:
Error C2078: too many initializes.
I have tried to dynamically allocate my array but nothing worked out so far as I am not too familiar with dynamic allocation. My question is If there is a possible way to declare an Array without an initial size and if so what is the most efficient way to do it ?
I wrote a simple program using pointers, new and delete functions. You can add more functionality to it.
#include <iostream>
using namespace std;
int main()
{
int size;
cout << "Input size of 2D array : ";
cin >> size;
int *ptr; // Declare Pointer
ptr = new int[size*size]; // Allocate memory of all elements in 2D array
for (int i = 0; i < size*size; i++) {
*(ptr + i) = 0; // Initialize every element to 0
}
cout << "Printing the 2D Array" << endl << endl;
int iterSize = 0;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
cout << *(ptr + iterSize) << " ";
}
cout << endl;
}
delete [] ptr; // ptr memory is released
return 0;
}
Here is the output initializing all elements to 0:
my question is If there is a possible way to declare an Array without an initial size and if so what is the most efficient way to do it ?
Sure, you could provide a vector of vectors to represent a 2D array (let's say of integer values):
std::vector<std::vector<int>> my2DArray;
Well, regarding efficiency maybe performance and memory fragmentation wise it's better to wrap a 1D vector kept internally with an interface that allows 2D coordinate access.
That would require you to know and specify the dimension limits though.
So if you really want to keep a 2D structure without initial size the above mentioned vector of vectors is the way to go.

Double (two-dimensional) array using std::unique_ptr

I have a double array allocated by pointer to pointer.
// pointer to pointer
int **x = new int *[5]; // allocation
for (i=0; i<5; i++){
x[i] = new int[2];
}
for (i=0; i<5; i++){ // assignment
for (j=0; j<2; j++){
x[i][j] = i+j;
}
}
for (i=0; i<5; i++) // deallocation
delete x[i];
delete x;
I am trying to do this using unique_ptr:
std::unique_ptr<std::unique_ptr<int>[]> a(new std::unique_ptr<int>[5]);
for (i=0; i<5; i++)
a[i] = new int[2];
but kept getting an error saying that no operator = matches these operands. What I am doing wrong here?
You cannot assign a int* to a std::unique_ptr<int[]>, that is the cause for your error. The correct code is
a[i] = std::unique_ptr<int[]>(new int[2]);
However, piokuc is correct, that it is highly unusual to use unique_ptr for arrays, as that's what std::vector and std::array are for, depending on if the size is known ahead of time.
//make a 5x2 dynamic jagged array, 100% resizable any time
std::vector<std::vector<int>> container1(5, std::vector<int>(2));
//make a 5x2 dynamic rectangular array, can resize the 5 but not the 2
std::vector<std::array<int, 2>> container1(5);
//make a 5x2 automatic array, can't resize the 2 or 5 but is _really fast_.
std::array<std::array<int, 2>, 5> container;
All of these can be initialized and used just the same as the code you already had, except they're easier to construct, and you don't have to destroy them.
If you do not have the luxury of using a std::array or a std::vector instead of a dynamically allocated array, you can use a std::unique_ptr for a two-dimensional array in C++11 as follows:
std::unique_ptr<int*, std::function<void(int**)>> x(
new int*[10](),
[](int** x) {
std::for_each(x, x + 10, std::default_delete<int[]>());
delete[] x;
}
);
The unique_ptr declaration takes care of allocating the row dimension of the array. The trailing () in new int*[10]() ensures that each column pointer is initialized to nullptr.
A for loop then allocates the column arrays:
for (size_t row = 0; row < 10; ++row) {
(x.get())[row] = new int[5];
}
When the unique_ptr goes out of scope, its custom deleter lambda function takes care of deleting the column arrays before deleting the row array. The for_each expression uses the default_delete functor.
for (i=0; i<5; i++) // deallocation
delete x[i];
delete x;
NO NO NO NO
delete [] x[i];
delete [] x;
// yo
The only reasons I can think of to use std::unique_ptr (or say boost::scoped_array) over std::vector for holding arrays are usually not applicable...
1) it saves 1 or 2 pointers worth of memory, depending on if you know what the size of all the arrays is [irrelevant unless you have a massive number of very small arrays]
2) in case you are just passing the array into some function that expects a C style array or raw pointer, it may feel like a more natural fit. std::vector IS guaranteed to be on sequential storage though, so passing (a.empty() ? nullptr : &a[0], a.size()) into such a function is 100% legit as well.
3) standard containers in MSVC debug mode are "checked" by default and very slow, which might be annoying when doing scientific programming on large datasets.
Your code is effectively manipulating an array of arrays of int.
In C++ you would normally want to implement it as:
std::vector<std::vector<int> > x;
This is not a good case for unique_ptr. Also, you should not need to use pointers to unique_ptr and allocate unique_ptr objects dynamically. The whole point of unique_ptr is to eliminate usage of pointers and to provide automatic allocation and deallocation of objects.
#include <iostream>
#include <memory>
#define print(x) std::cout << x
#define println(x) std::cout << x << std::endl
int main() {
std::unique_ptr<std::unique_ptr<int[]>[]> arr(new std::unique_ptr<int[]>[2]());
for (int i = 0; i < 2; i++)
{
arr[i] = std::make_unique<int[]>(5);
for (int j = 0; j < 5; j++) {
arr[i][j] = j;
println(arr[i][j]);
}
println(arr[i]);
}
}
An example further up inspired me for this solution
size_t k = 10;
std::unique_ptr<int*, std::function<void(int**)>> y(new int*[k](),
[](int** x) {delete [] &(x[0][0]);
delete[] x;});
// Allocate the large array
y.get()[0] = new int[k*10];
// Establish row-pointers
for (size_t row = 0; row < k; ++row) {
(y.get())[row] = &(y.get()[0][0]);
}
Here all dimensions can be dynamic and you can wrap it inside a class and expose an operator[]. Also the memory is allocated in a contiguous manner and you can easily introduce an allocator, which allocates aligned memory.
for (i=0; i<5; i++) // deallocation
delete x[i];
delete x;
It is a common mistake here.
x[i] is an array so you have to delete each array first using delete[]
Then you can delete you array of int* by using delete[]
Correct desallocation would be:
for (i=0; i<5; i++)
delete[] x[i]; //desallocate each array of int
delete[] x; //desallocate your array of int*
x = nullptr; //good practice to be sure it wont cause any dmg