How to declare a dynamic 2D array in C++ - c++

I'm trying to define a dynamic 2D Array in C++ using the following definition:
int foo(string parameter){
const int n = parameter.length();
int* Array = new int[n][n];
return 0;
}
I receive an error that array size in new expression must be constant, can't understand why because Array is supposed to be dynamic.

(someone posted a shorter version of this in the comments while I was writing it).
What you need for a 2D array allocated with new is this:
int foo(string parameter){
const int n = parameter.length();
int* Array = new int[n*n];
return 0;
}
And then access cells with appropriate indexing.
Another solution is to use vector.
int foo(string parameter){
const int n = parameter.length();
vector<vector<int>> Array(n, vector<int>(n));
return 0;
}

Related

Pointer casting with unknown array size in C++

how can I cast void pointer to a 2d array (array of pointers to arrays of ints), when I dont know array size at compile time? Is it somehow possible? (I am doing this because, I pass an 2d array of unknow size to a func. So I cast 2d array to a void pointer and then in that func I want it to recast back.)
int i = 5;
int tab1[i][i];
//cast to void pointer
void *p = (void *)tab1;
//and recast back
int (*tab2)[5] = (int (*)[5])p; //this is working
int (*tab3)[i] = (int (*)[i])p; // but this is not
First I suggest to don't use runtime size for array in C/C++, except you using STL vector as an array. so instead of:
int i = 5;
you must use:
const int i = 5;
except you use Vector that is safe and better than intrinsic arrays.
how can I cast void pointer to a 2d array (array of pointers to arrays of ints), when I dont know array size at compile time? Is it somehow possible?
If we talk about C intrinsic array, It is not possible!
why it is not possible?
because C/C++ compiler not aware of your the array size, borders,.... so if you cast your 2d array to 1d array, it is possible. it is the reason that tab2 array can access to first 5th element of your array. really C/C++ compiler cannot distinguish the different of
int a[3][3]
with
int a[3*3]
so You must be aware of at least one dimension of your array:
int main() {
const int i = 3,j = 4;
int tab1[i][j] = {1,2,3,4,5,6,7,8,9,10,11};
//cast to void pointer
void *p = (void *)tab1;
auto a = (int (*)[i][12/i])p;
return 0;
}
In the above example, I aware about i and total count(12) and I calculate the second dimension.
I use auto keyword that very easily inferred the data type.
int i = 5; int tab1[i][i]; is a VLA. It's not standard C++ and should be avoided.
An array-of-pointers-to-arrays (and vector-of-vectors) won't be as efficient as a true 2D array since it's no longer contiguous (int tab1[5][5] is a true 2D array and is stored contiguously in memory, but the dimensions must be known at compile-time).
You can easily create a custom 2D container class that would store the data in a contiguous 1D vector and apply some simple math (x + y*width) to access the elements.
Example:
class Matrix {
std::vector<int> data;
public:
const int width;
const int height;
Matrix(int width, int height) : width(width), height(height), data(width*height) {}
int operator()(int x, int y) const {
return data[y * width + x];
}
int& operator()(int x, int y) {
return data[y * width + x];
}
};
void print(Matrix const& mat) {
for (int y = 0; y < mat.height; y++) {
for (int x = 0; x < mat.width; x++)
std::cout << mat(x, y) << " ";
std::cout << std::endl;
}
}
int main() {
Matrix mat(5, 5);
mat(1, 1) = 1;
mat(2, 2) = 2;
mat(3, 3) = 3;
print(mat);
}
For convenience this overloads the () operator. It's still possible with the [] operator but that will require a proxy class to access the inner dimension(s) and also putting y before x since the dimensions are actually reversed.
int tab1[i][i]; is a non-standard compiler extension for variable length arrays. It is better to avoid this because it is not portable and hard to deal with as you are seeing. You would be better with:
std::vector<std::vector<int>> tab1(i, std::vector<int>(i));
Then your function can simply take this vector:
void foo(const std::vector<std::vector<int>>& array) { ....
how can I cast void pointer to a 2d array (array of pointers to arrays of ints), when I dont know array size at compile time?
You can't. You can only cast to a type that is known at compile time.
What you can do is convert to a pointer to first element of the first row: int* p = static_cast<int*>(tab1);. You can then treat the array as one dimensional1. Converting two dimensional indices to one dimensional requires some trivial math: x, y -> x + y * i.
1 As long as you don't mind the technicality that pointer arithmetic across the sub array boundary might technically not be allowed by the standard. But that rule is silly. If you're concerned about this, then you should create a one dimensional array in the first place.
The problem you are having here is that the size of an array must be defined at compile time.
In your case, you have multiple options:
make i a constexpr like constexpr int i = 5;
use a int ** instead:
int i = 5;
int tab1[i][i];
//cast to void pointer
void *p = (void *)tab1;
// cast to int **
auto tab1_p = (int **)p;
// use it like it was an array
tab1_p[1][3] = 5;

Access violation writing location 0xCCCCCCCC creating 2d array

I'm trying to make a dynamic 2-dimensional array.
Here is my code:
bool b_alloc_table_2_dim(int ***piTable, int iSizeX, int iSizeY)
{
*piTable = new int*[iSizeX];
for (int ii = 0; ii < iSizeX; ii++)
*piTable[ii] = new int[iSizeY]; // here i get the exception
return true;
}
int main()
{
int **x ;
b_alloc_table_2_dim( &x, 3, 5);
return 0;
}
I can't find anything wrong with the code. After calling my function x is supposed to point to the 2d array.
The [] operator takes precedence over *. cppreference
So the line
*piTable[ii] = new int[iSizeY];
is equivalent to
*(piTable[ii]) = new int[iSizeY];
what you wanted to write is:
(*piTable)[ii] = new int[iSizeY];
Use an actual container
Using an actual container avoids a lot of the types of issues that you have encountered.
Instead of
int**
For a 2d array (a matrix) a more suitable data structure could be
std::array< std::array<int, cols>, rows>
if the sizes is known at compile time.
If not, it's probably best to just use a single vector ala.
auto my_array2d = std::vector<int>(rows*cols);//array now has 'rows*cols' elements of '0'
and handle indexing yourself.
The best thing is of course to use a library like perhaps eigen or boost

How to dynamically allocate a contiguous 2D array in C++?

I need a 2d character array for use in a trash API that absolutely requires use of arrays and NOT vectors (much emphasis on this because all of my searching just had answers "use a vector". I wish I could).
I figured the way to do it would be to allocate an external array of size rows * character length, instead of doing:
char** arr;
arr = new char*[100];
// for loop that allocates the internal arrays
But I'm not sure what method I would need to use to make it contiguous? Do I need to allocate a massive 1D array first, then assign the 1D array to the 2D array in chunks?
As other answers have said: allocate n * m entries to create the contiguous data, and then it can be wrapped in pointers to create a 2d array.
... absolutely requires use of arrays and NOT vectors ...
I'm not sure if vector is a constraint based on the API being used, or requirements -- but it's worth noting that vector can be used for the memory management of the implementation -- while still using the raw data (which can be accessed by &vec[0] or vec.data(), which returns a pointer to the first element of the array, and can be used with functions accepting raw pointers).
Since this question is about c++, one option is to wrap an array of n * m in a class that acts like a 2-d array while actually being contiguous.
A simple example could be:
class array_2d
{
public:
array_2d( std::size_t rows, std::size_t columns )
: m_rows(rows), m_cols(columns), m_array( new char[rows * columns] )
{
}
~array_2d()
{
delete [] m_array;
}
// row-major vs column-major is up to your implementation
T& operator()( std::ptrdiff_t row, std::ptrdiff_t col )
{
// optional: do bounds checking, throw std::out_of_range first
return m_array[row * m_cols + col];
// alternatively:
// return m_array[col * m_rows + row];
}
// get pointer to the array (for raw calls)
char* data()
{
return m_array;
}
private:
char* m_array;
std::size_t m_rows;
std::size_t m_cols;
};
(Ideally char* would be std::unique_ptr<char[]> or std::vector<char> to avoid memory-leak conditions, but since you said vector is not viable, I'm writing this minimally)
This example overloads the call operator (operator()) -- but this could also be a named function like at(...); the choice would be up to you. The use of such type would then be:
auto array = array_2d(5,5); // create 5x5 array
auto& i01 = array(0,1); // access row 0, column 1
Optionally, if the [][] syntax is important to behave like a 2d-array (rather than the (r,c) syntax), you can return a proxy type from a call to an overloaded operator [] (untested):
class array_2d_proxy
{
public:
array_2d_proxy( char* p ) : m_entry(p){}
char& operator[]( std::ptrdiff_t col ){ return m_entry[col]; }
private:
char* m_entry;
};
class array_2d
{
...
array_2d_proxy operator[]( std::ptrdiff_t row )
{
return array_2d_proxy( m_array + (row * m_cols) );
}
...
};
This would allow you to have the 'normal' 2d-array syntax, while still being contiguous:
auto& i00 = array[0][0];
This is a good way to do it:
void array2d(int m, int n) {
std::vector<char> bytes(m * n);
std::vector<char*> arrays;
for (int i = 0; i != m * n; i += n) {
arrays.push_back(bytes.data() + i);
}
char** array2d = arrays.data();
// whatever
}
The main problem in C++ with "continuous 2d arrays with variable column length" is that an access like myArray[r][c] requires the compiler to know the column size of the type of myArray at compile time (unlike C, C++ does not support variable length arrays (VLAs)).
To overcome this, you could allocate a continuous block of characters, and additionally create an array of pointers, where each pointer points to the begin of a row. With such a "view", you can then address the continuous block of memory indirectly with a myArray[r][c]-notation:
int main() {
// variable nr of rows/columns:
int rows = 2;
int columns = 5;
// allocate continuous block of memory
char *contingousMemoryBlock = new char[rows*columns];
// for demonstration purpose, fill in some content
for (int i=0; i<rows*columns; i++) {
contingousMemoryBlock[i] = '0' + i;
}
// make an array of pointers as a 2d-"view" of the memory block:
char **arr2d= new char*[rows];
for (int r=0; r<rows;r++) {
arr2d[r] = contingousMemoryBlock + r*columns;
}
// access the continuous memory block as a 2d-array:
for (int r=0; r<rows; r++) {
for (int c=0; c<columns; c++) {
cout << arr2d[r][c];
}
cout << endl;
}
}

How to dynamically allocate a 2D array in C++?

How to create a 2d array using dynamic memory allocation in c++?
Maze(int c=10){
const int m=c;
a=new int[m][m];
}
void main(){
Maze(12);
}
std::vector is the typical way to have a dynamically allocated array in C++. You can have a vector of vectors to make it two-dimensional. Here's an example:
std::vector<std::vector<int>> a(m,std::vector<int>(m));
If you want it inside a class:
struct Maze {
std::vector<std::vector<int>> a;
Maze(int m) : a(m,std::vector<int>(m)) { }
};
Easily - using multiplication. Also I suggest using reference to array because in this way you specify the type more explicitly then using a pointer to it's first element. I'm actually amazed why this isn't the type most programmers use. Perhaps because they're lazy and the type is complex ;).
void Maze(int c=10) {
const int m=c;
int (&a)[0][0] = *(int (*)[0][0])new int[/*numbers of rows*/ m * sizeof(int) * m /* number of colums on each row*/];
}
Here 'a' is an reference to the newly created array. As types aren't dynamic in 'C++' language we assume that it has zero elements on each of it's dimensions. But of-course we can access more then 0.
Now if you have a function with parameter of type 2 dim array it will look like this:
void func(int (&_2dimarray)[0][0]) ;
Or if you want to return it from your 'Maze' you could write:
int (&Maze(int c=10))[0][0] {
const int m=c;
int (&a)[0][0] = *(int (*)[0][0])new int[/*numbers of rows*/ m * sizeof(int) * m /* number of colums on each row*/];
return a;
}
Life example.
But of-course the easiest way is using 'std::vector' which however can have performance cost on some compilers while the built-in array will more surely run fast everywhere.
EDIT: The explanation is simple - the 'new []' can be thought as a function like:
template<class T>
T *operator new T[] (std::size_t);
Your instance of it:
a=new int[m][m];
Can also look like this (illustrative)
a=operator new int[m][](m);
Which fulfills 'T' with 'int[m]'.
This is illegal because 'int[m]' is not valid type. 'C++' supports only static types and this is not such because the length of the array can't be determined during compile-time as 'm' is not a constant. The last 'm' is a function parameter to 'operator new[]'.
Yep I also think this construct isn't the most elegant yet but this is the life.
There are two approaches. If the size of the internal one-dimensional subarray is a constant value known at compile time then you can write
const size_t N = 10;
int ( * )[N] Maze( size_t n = N )
{
return new int[n][N];
}
int main()
{
int ( *a )[N] = Maze( 12 );
//...
delete [] a;
}
If it is not a constant then you need to allocate a one-dimensional array of pointers to one-dimensional arrays. For example
const size_t N = 10;
int ** Maze( size_t n = N )
{
int **p = new int *[n];
for ( size_t i = 0; i < n; i++ ) p[i] = new int[n];
return p;
}
int main()
{
int **a = Maze( 12 );
//...
for ( size_t i = 0; i < 12; i++ ) delete [] a[i];
delete [] a;
}
Also you could use smart pointers as for example std::unique_ptr.
The other approach is to use standard container std::vector<std::vector<int>>

2D array as instance variable of class

So if I have a class with a 2D array that I want to initialize with two parameters passed into the constructor, how would I do that, I keep running into errors because it won't let me update the two-d array at all in the constructor.
-- Update from the comments:
In my header file I tried both
int array[][]
and
int **array
and then in the .cpp file in the constructor I'm trying to do
array = new int[arg1][arg2]
Neither declaration of the array in the header file worked.
in the constructor I'm trying to do array = new array[arg1][arg2]
You need to specify the array type, like
array = new int[arg1][arg2];
Note that this works in C++11 only - when using older standards, the second array size needs to be const (which is probably not what you want).
There are also some additional articles discussing the same issue:
Multi-Dimensional Arrays
How to "new" a two-dimension array in C++?
Ideally, since you are using C++ anyway, you should use std::vector as proposed in another answer.
Vectors use a lot of overhead though, don't they? I'm trying to keep my memory use light. –
Start with std::vector. Once your application is running properly from a functional perspective, if you are still concerned about memory usage and/or performance, do benchmarking. If you properly encapsulate your 2D array in a class, you can always change the actual implementation of the array with no impact on the code which uses it.
Technically, if you want to make sure that you have one flat memory area which contains your array, you could use a 1-dimensional array to simulate a 2-dimensional array, like in the following code (just to get you the idea, certainly needs some improvement, especially copy construction and assignment operators are missing):
class Array2D {
private:
int *array;
int size1;
public:
Array2D(int arg1, int arg2) {
size1 = arg1;
array = new int[arg1 * arg2];
}
~Array2D() {
delete[] array;
}
int& at(int i1, int i2) {
return array[i1 * size1 + i2];
}
};
int main() {
Array2D array(10, 10);
array.at(2, 2) = 42;
std::cerr << array.at(2, 2);
return 0;
}
Simplest solution would be:
std::vector<std::vector<VALUE>> arr2(X, std::vector<VALUE>(Y));
Here is an 2d array example with bounds check and custom type, based upon the example from Andreas Fester.
#include <stdexcept>
template <typename T>
class Array2D {
private:
T *array;
unsigned int sizeX;
unsigned int sizeY;
public:
Array2D(unsigned int X, unsigned int Y) {
sizeX = X;
sizeY = Y;
array = new T[X * Y];
}
~Array2D() {
delete[] array;
}
T& at(unsigned int X, unsigned int Y) {
if((X > sizeX) || (Y > sizeY))
throw std::out_of_range("Bla bla");
return array[X * sizeX + Y];
}
};
int main() {
double MyValue;
Array2D<double> *MyArray = new Array2D<double>(10, 100);
MyArray->at(1,1) = 10.1;
MyValue = MyArray->at(1,1);
printf("Array value = %3.3f\n", MyValue);
return 0;
}