The correct way to initialize a dynamic pointer to a multidimensional array? [duplicate] - c++

This question already has an answer here:
How to properly work with dynamically-allocated multi-dimensional arrays in C++ [duplicate]
(1 answer)
Closed 7 years ago.
I've been having bad luck with with dynamic pointers when I range them to 2 dimensions and higher. For example I want a pointer to a 2D array. I know that:
int A[3][4];
int (*P)[4] = A;
Is completely legit (even if I don't completely understand why). Taking into consideration that:
int *P = new int[4];
works, I imagined that:
int **P = new int[5][7];
Would also work, but it's not. This code states the error:
Error: A value of type "(*)[7]" cannot be used to initialize an entity of
type "int **"
By seeing this the new part becomes a pointer to an array of 7 integers I made:
int (*P)[4] = new int[7][4];
And this does work but it's not what I want to accomplish. By doing it like that I'm limited to at least using a constant value for any subsequent dimension, but I want it to be fully defined at run time and therefore "dynamic".
How could I go and make this multidimensional pointer work??

Let's start with some basic examples.
When you say int *P = new int[4];
new int[4]; calls operator new function()
allocates a memory for 4 integers.
returns a reference to this memory.
to bind this reference, you need to have same type of pointer as that of return reference so you do
int *P = new int[4]; // As you created an array of integer
// you should assign it to a pointer-to-integer
For a multi-idimensional array, you need to allocate an array of pointers, then fill that array with pointers to arrays, like this:
int **p;
p = new int*[5]; // dynamic `array (size 5) of pointers to int`
for (int i = 0; i < 5; ++i) {
p[i] = new int[10];
// each i-th pointer is now pointing to dynamic array (size 10)
// of actual int values
}
Here is what it looks like:
To free the memory
For one dimensional array,
// need to use the delete[] operator because we used the new[] operator
delete[] p; //free memory pointed by p;`
For 2d Array,
// need to use the delete[] operator because we used the new[] operator
for(int i = 0; i < 5; ++i){
delete[] p[i];//deletes an inner array of integer;
}
delete[] p; //delete pointer holding array of pointers;
Avoid memory leakage and dangling pointers!

You want something like:
int **P = new int*[7];
p[0] = new int[5];
p[1] = new int[5];
...

Another approach would be to use a 1D array as an 2D array. This way you only have to allocate the memory once (one continous block);
int *array;
size_t row=5,col=5;
array = (int*)malloc(row*col*sizeof(int)) //or new int[row*col]
This would result in the same as "int array[5][5]".
to access the fields you just do:
array[1 //the row you want
* col //the number of columns
+2//the column you want
] = 4;
This is equal to:
array[1][2];

This performs bounds checking on some debug compilers, uses dynamic size and deletes itself automatically. The only gotcha is x and y are the opposite way round.
std::vector<std::vector<int>> array2d(y_size, std::vector<int>(x_size));
for (int y = 0; y < y_size; y++)
{
for (int x = 0; x < x_size; y++)
{
array2d[y][x] = 0;
}
}

Related

Why do I have to free 2D array twice to avoid memory leak?

I am running into a memory leak problem when allocating a 2D array.
But I could not understand why the memory leaks.
My reasoning is that at Note A, I have already freed allocated memory, since data_[0] == data_, why do I have to do the free at Note B?
class Matrix {
public:
Matrix(int r, int c) {
this->rows = r;
this->cols = c;
data_ = new int*[r];
for (int i = 0; i < r; i++) {
data_[i] = new int[c];
}
}
~Matrix() {
for (int i = 0; i < this->rows; i++) {
delete [] data_[i]; // Note A;
}
delete[] data_; // Note B; <-- not doing this line will leak memory, but why?
}
private:
int rows;
int cols;
int **data_;
};
What you post there isn't really a 2D array, it's a 1D array-of-pointers (data_), and then you allocate a separate array-of-ints for each element of the first array (so data_[0] is an array of c ints, data_[1] is an array of c ints, and so on).
Given that, it's natural that you'll have to do one delete[] in your destructor for each new that you performed earlier in your constructor.
A graphical diagram of your memory allocations and how they point to each other might look like this (if c==6 and you have set all of your arrays' integers to 0):
A real 2D array allocation would look like this: int * array2D = new int[6][8];, but of course C++ only supports 2D arrays if the array-dimenions are compile-time constants, so that probably wouldn't solve the problem your Matrix class is meant to solve.
When you have created 2D array (for example 3x3), you have created 1 array with 3 elements, where each element is pointer to separate array. So to clear memory for this matrix you need to clear 4 arrays (3 rows and 1 array containing pointers).
You can check how many times in your code you are calling new operator
it will be r+1 times
data_ = new int*[r];// 1 time
for (int i = 0; i < r; i++ {
data_[i] = new T[c]; // r times
}
Part I:
The line data_ = new int*[r]; allocates and default initializes a dynamic array of int* through new, so you would need to provide a corresponding delete [] data_; for this line.
Part II:
The line data_[i] = new int[c]; dynamically allocates and default initializes an int array and then the pointer to that first element is returned and stored as the data_[i] element. So here again you would need a corresponding delete [] data_[i]; to get rid of the memory leak.
So these were the reasons why you need two separate delete []. The process is as shown in the screenshot. Also note that the important thing is the default initialization. So the int array elements will not all have a value 0 as wrongly shown in the answer by #Jeremy Friesner.

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;
}

Constant for a multi-dimensional array

I'm trying to create a multi-dimensional array, the size of which the user will supply.
So far I have this:
int definedgroups; // for number of groups needed
cout << "Enter the Number of Groups you require: " << endl;
cin >> definedgroups;
const int definedgroups = definedgroups;
int User_Groups [definedgroups] [4];
I believe the array needs constant values, so i tried assigning my variable as a constant but still no luck.
In C++, static arrays, that is, those defined like this:
foo arrayStatic[bar];
require bar to be a constant integer. In other words, the programmer needs to know its value beforehand.
Whenever bar is unknown, a dynamic array could be used instead. They're defined like this:
foo* arrayDynamic;
arrayDynamic = new foo[bar];
Here, bar could be an integer variable.
Don't forget that dynamic memory must be deallocated eventually. So, in this case, we can deallocate arrayDynamic like this:
delete [] arrayDynamic;
A two-dimensional dynamic array is defined analogously:
foo** arrayDynamic2D;
arrayDynamic2D = new foo*[bar];
for (int i = 0; i < bar; i++)
arrayDynamic2D[i] = new foo[baz];
and deallocated in a similar fashion:
for (int i = 0; i < bar; i++)
delete [] arrayDynamic2D[i];
delete [] arrayDynamic2D;
Static memory is allocated in the stack whereas dynamic memory is allocated in the heap.
It's not possible to do it in C++ using static arrays. Use std::vector in a hierarchical way (i.e. vectors of vectors) to implement a multi-dimensional array easily (though not necessarily very efficiently).
E.g.
std::vector<std::vector<double> > array(nrows, std::vector<double>(ncols));
creates a nrows x ncols matrix.
You need dynamic memory allocation using new:
int **User_Groups = new int*[definedgroups];
//Allocate memory for 2nd dimension
for (int i = 0; i < 4; ++i)
User_Groups[i] = new int[4];

allocation of a pointers to fixed size arrays

I have 2 doubts regarding basics of pointers usage.
With the following code
int (*p_b)[10];
p_b = new int[3][10];
// ..do my stuff
delete [] p_b
p_b is pointing to an array of 3 elements, each having fixed-size length of 10 int.
Q1:
How to declare p_b if I want that each element be a pointer to a fixed array size?
Basically I want the following
p_b[0] = pointer to a fixed-array size of 10
p_b[1] = pointer to a fixed-array size of 10
// ... and so on
I was thinking to int (** p_b)[10] but then I don't know how to use new to allocate it? I would like to avoid falling back to more general int** p_b
Q2:
Is per my original code sample above, how to call new so that p_b points to a unique fixed-size array of 10 int other than calling p_b = new int[1][10] ? To free memory I have to call delete[] while I cannot find an expression where I can call only simply delete.
p_b is pointing to an array of 3 elements, each having fixed-size length of 10 int.
How to declare p_b if I want that each element be a pointer to a fixed array size?
Does your first sentence not completely cover that question?
Is per my original code sample above, how to call new so that p_b points to a unique fixed-size array of 10 int other than calling p_b = new int[1][10]? To free memory I have to call delete[] while I cannot find an expression where I can call only simply delete.
I completely do not understand why this is a problem, but you could do it by wrapping your array inside another type... say std::array, boost::array or std::vector.
First of all, if your new expression has square brackets (new somtype[somesize]), your delete has to have square brackets as well (delete [] your_pointer).
Second, right now you've defined p_b to be a single pointer to some data. If what you really want is an array of pointers, then you need to define it as an array. Since you apparently want three independent arrays, you'll have to allocate each of them separately. It's probably easiest if you start with a typedef:
typedef int *p_int;
p_int p_b[3];
Then you'll allocate your three arrays:
for (int i=0; i<3; i++)
p_b[i] = new int[10];
To delete those, you'll need to delete each one separately:
for (int i=0; i<3; i++)
delete [] p_b[i];
I definitely agree with #Tomalak that you should almost never mess with things like this yourself though. It's not clear what you really want to accomplish, but it's still pretty easy to guess that chances are quite good that a standard container is likely to be a simpler, cleaner way to do it anyway.
Here's an example of how to implement Q1:
int main()
{
typedef int foo[10];
foo* f = new foo[3];
f[0][5] = 5;
f[2][7] = 10;
delete [] f;
}
As for Q2, the only way to delete memory allocated with new[] is with delete[]. If you personally don't want to write delete [], you can use a vector or another STL container. Really, unless this is some hardcore uber-optimisation, you should be using vectors anyway. Never manage memory manually unless you are absolutely forced to.
To use a raw pointer to manage a 2-d array you must first create a pointer to a pointer to array element type that will point to each row of the array. Next, each row pointer must be assigned to the actual array elements for that row.
int main()
{
int **p;
// declare an array of 3 pointers
p = new int*[3];
// declare an array of 10 ints pointed to by each pointer
for( int i = 0; i < 3; ++i ) {
p[i] = new int[10];
}
// use array as p[i][j]
// delete each array of ints
for( int i = 0; i < 3; ++i ) {
delete[] p[i];
}
// delete array of pointers
delete[] p;
}
A far easier solution is to use std::array. If your compiler does not provide that class you can use std::vector also.
std::array<std::array<int,10>,3> myArr;
myArr[0][0] = 1;
For Q1, I think you want
int (*p[3])[10];
Try cdecl when you're unsure.
Your other question seems to be well answered by other answers.
regards,
Yati Sagade
Actually, nobody posted an answer to your exact question, yet.
Instead of
int (*p_arr)[10] = new int[3][10];
// use, then don't forget to delete[]
delete[] p_arr;
I suggest using
std::vector<std::array<int, 10>> vec_of_arr(3);
or if you don't need to move it around and don't need runtime length:
std::array<std::array<int, 10>, 3> arr_of_arr;
Q1
How to declare p_b if I want that each element be a pointer to a fixed array size?
int(**pp_arr)[10] = new std::add_pointer_t<int[10]>[3];
for (int i = 0; i < 3; ++i)
pp_arr[i] = new int[1][10];
// use, then don't forget to delete[]
for (int i = 0; i < 3; ++i)
delete[] pp_arr[i];
delete[] pp_arr;
The modern variant of that code is
std::vector<std::unique_ptr<std::array<int, 10>>> vec_of_p_arr(3);
for (auto& p_arr : vec_of_p_arr)
p_arr = std::make_unique<std::array<int, 10>>();
or if you don't need to move it around and don't need runtime length:
std::array<std::unique_ptr<std::array<int, 10>>, 3> arr_of_p_arr;
for (auto& p_arr : arr_of_p_arr)
p_arr = std::make_unique<std::array<int, 10>>();
Q2
Is per my original code sample above, how to call new so that p_b points to a unique fixed-size array of 10 int other than calling p_b = new int[1][10]?
Not without wrapping the array into another type.
std::array<int, 10>* p_arr = new std::array<int, 10>;
// use, then don't forget to delete
delete p_arr;
You can replace std::array<int, 10> with your favourite array-wrapping type, but you cannot replace it with a fixed-size array alias. The modern variant of that code is:
auto p_arr = std::make_unique<std::array<int, 10>>();

Convert char** to char[x][x]

In C++, I want my class to have a char** field that will be sized with user input. Basically, I want to do something like this -
char** map;
map = new char[10][10];
with the 10's being any integer number. I get an error saying cannot convert char*[10] to char**. Why can it not do this when I could do -
char* astring;
astring = new char[10];
?
Because an array is not a pointer. Arrays decay into pointers to their first elements, but that happens only at the first level: a 2D array decays into a pointer to a 1D array, but that's it—it does not decay into a pointer to a pointer.
operator new[] allows to allocate a dynamic array of a size only known at runtime, but it only lets you allocate 1D arrays. If you want to allocate a dynamic 2D array, you need to do it in two steps: first allocate an array of pointers, then for each pointer, allocate another 1D array. For example:
char **map = new char*[10]; // allocate dynamic array of 10 char*'s
for(int i = 0; i < 10; i++)
map[i] = new char[10]; // allocate dynamic array of 10 char's
Then to free the array, you have to deallocate everything in reverse:
for(int i = 0; i < 10; i++)
delete [] map[i];
delete [] map;
On other hand, what the
map = new char[x][y];
really do is that, you new a array contain x items whose type is an array containing y items. And y must be a const integer.
So, if you really want your code pass without any problem, the correct way is
char (* map)[10] ;
map = new char[some_value_you_want][10];
Or more clearly,
typedef char array10[10];
array10 * map = new array10[some_value_you_want];
Multi-dimentional arrays are not supported in that manner. You need to allocate the two dimentions seperately.
char** map = new (char*)[10];
for( int i = 0; i < 10; ++i ) {
map[i] = new char[10];
}