I need a 2d array with fixed width and height that can only change the individual values stored in it. It is declared in a header and later initialized in a source file.
What I found made me try the following snippets; unfortunately questions were about either 1d or non-const arrays and did not match my situation.
int *const *const a = new int[10][10];
int *const *const b = new int[10][10]();
int *const *const c = new int*[10];
for (int i = 0; i < 10; ++i) {
c[i] = new int[10];
}
My hope was in the last example, but how can I use the "inner" arrays of c if they are not initialized and I am not able to initialize them since they are const?
Do I not need a different type for this array? I was thinking about int d[][] but it doesn't have constant width and height.
It seems to me like a paradox (if it exists in the c++ world), am I missing something?
I was thinking about int d[][] but it doesn't have constant width and height.
int d[][] does not make sense (and will be rejected by the compiler). As far as multi-dimensional arrays are concerned, only the first dimension's size can be omitted to denote an incomplete type. The other dimensions' sizes are part of the type. You cannot omit them, much like you cannot omit the int.
In other words, if you have something like int d[5][10], then you can think of it as a one-dimensional array of element type int[10]. Generally, think of multi-dimensional arrays as a special case of one-dimensional arrays. It will make everything easier to understand.
The best solution to your problem in C++ is to create a class with private std::array<T, Width * Height> data; and int width member variables inside, and calculate the array offset from individual x and y arguments in a public member function, for example:
T& operator()(int x, int y)
{
return data[y * width + x];
}
If the dimensions are only known at run-time, then the only thing you have to change is using std::vector instead of std::array. Storage will still be contiguous.
Here is a complete example:
#include <vector>
#include <iostream>
class Matrix
{
public:
Matrix(int width, int height, int value) :
width(width),
data(width * height, value)
{}
int& operator()(int x, int y)
{
return data[y * width + x];
}
private:
int width;
std::vector<int> data;
};
int main()
{
Matrix m(5, 10, 123);
std::cout << m(7, 8) << "\n";
m(7, 8) = 124;
std::cout << m(7, 8) << "\n";
}
My hope was in the last example, but how can I use the "inner" arrays of c if they are not initialized and I am not able to initialize them since they are const?
That's not really true at all:
int * const * const c = new int*[10]
{
new int[10], new int[10], new int[10], new int[10], new int[10],
new int[10], new int[10], new int[10], new int[10], new int[10]
};
Related
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;
I want to create a dynamic 2d array in a separate function. The size of the array will be determined at runtime.
Pass an array directly:
void foo(int **arr,int width,int height)
{
arr=new int*[width];
for(int i=0;i<height;i++)
{
arr[i]=new int[height];
}
//fill...
}
...
int** array;
foo(array)
doesn't seem to work
Pass an array via a pointer
void foo(int ***arr,int width,int height)
{
*arr=new int*[width];
for(int i=0;i<height;i++)
{
*arr[i]=new int[height];
}
//fill...
}
...
int **array;
foo(&array)
doesnt seem to work either
How do I do that?
I think that your "problem" is caused by ignoring operator precedence
Second code you posted seems to have mistake on line with:
*arr[i]=new int[height];
which should be
(*arr)[i]=new int[height];
Also, as other pointed out, working with raw pointers could sometimes be pretty evil (like in your example with Pointer to Pointer to Pointer), raw pointers could also cause some problems with memory leaks, dangling pointers,etc. Use something "more practical" like std::vector or some of the other STL containers.
(Note: By term "STL", I mean part of Standard library based on STL)
Let's assume you have to create 2d arrays this way (with an int**).
Instead of trying to pass pointers, return the value that denotes the 2d array.
Second, your code had a bug in that you were looping over the height when you should be looping over the width. Your code would have gone into undefined behavior if height > width.
Third, I don't know if you meant width to be the first dimension or height to be the first dimension, so let's assume that what you wrote is what you meant, i.e. width is the first dimension and height is the inner dimension.
int **foo(int width, int height)
{
int **arr = new int*[width];
for(int i=0; i<width; i++)
arr[i]=new int[height];
return arr;
}
//....
int width = 10, height = 10;
int** array = foo(width, height);
Then you have to write code to delete the allocated data:
for (int i = 0; i < width; ++i)
delete [] array [i];
delete [] array;
Now having said the above, and the above should work, a more optimal version is found here, where the data is one contiguous block instead of separate allocated blocks. This reduces the number of times new[] and delete [] would need to be called.
Generally speaking, multidimensional arrays should never, never be created like this. You should be using a single array wrapped in an object that provides row, column, table, etc. access using the operator() function.
You should also never, never be using raw pointers (except in weird, extenuating circumstances) which is why I'm using STL's std::vector class to implement your code.
class array_2d {
public:
array_2d(size_t width, size_t height) :
width(width),
height(height),
_array(width * height)
{}
int & operator()(size_t x, size_t y) {
return _array[y * width + x];
}
const int & operator()(size_t x, size_t y) const {
return _array[y * width + x];
}
std::pair<size_t, size_t> get_size() const {
return std::make_pair<size_t, size_t>(width, height);
}
private:
size_t width, height;
std::vector<int> _array;
};
int main() {
array_2d my_array(5,5);
my_array(3,3) = 7;
std::cout << my_array(3,3) << std::endl;
return 0;
}
====
7
There's a lot of stuff I didn't include (and the code would be significantly more complex if you were to implement this as a raw pointer) but this is a far superior way to write a 2-dimensional (or more dimensions, if you need it) array.
I have come across some code which allocates a 2d array with following approach:
auto a = new int[10][10];
Is this a valid thing to do in C++? I have search through several C++ reference books, none of them has mentioned such approach.
Normally I would have done the allocation manually as follow:
int **a = new int *[10];
for (int i = 0; i < 10; i++) {
a[i] = new int[10];
}
If the first approach is valid, then which one is preferred?
The first example:
auto a = new int[10][10];
That allocates a multidimensional array or array of arrays as a contiguous block of memory.
The second example:
int** a = new int*[10];
for (int i = 0; i < 10; i++) {
a[i] = new int[10];
}
That is not a true multidimensional array. It is, in fact, an array of pointers and requires two indirections to access each element.
The expression new int[10][10] means to allocate an array of ten elements of type int[10], so yes, it is a valid thing to do.
The type of the pointer returned by new is int(*)[10]; one could declare a variable of such a type via int (*ptr)[10];.
For the sake of legibility, one probably shouldn't use that syntax, and should prefer to use auto as in your example, or use a typedef to simplify as in
using int10 = int[10]; // typedef int int10[10];
int10 *ptr;
In this case, for small arrays, it is more efficient to allocate them on the stack. Perhaps even using a convenience wrapper such as std::array<std::array<int, 10>, 10>. However, in general, it is valid to do something like the following:
auto arr = new int[a][b];
Where a is a std::size_t and b is a constexpr std::size_t. This results in more efficient allocation as there should only be one call to operator new[] with sizeof(int) * a * b as the argument, instead of the a calls to operator new[] with sizeof(int) * b as the argument. As stated by Galik in his answer, there is also the potential for faster access times, due to increased cache coherency (the entire array is contiguous in memory).
However, the only reason I can imagine one using something like this would be with a compile-time-sized matrix/tensor, where all of the dimensions are known at compile time, but it allocates on the heap if it exceeds the stack size.
In general, it is probably best to write your own RAII wrapper class like follows (you would also need to add various accessors for height/width, along with implementing a copy/move constructor and assignment, but the general idea is here:
template <typename T>
class Matrix {
public:
Matrix( std::size_t height, std::size_t width ) : m_height( height ), m_width( width )
{
m_data = new T[height * width]();
}
~Matrix() { delete m_data; m_data = nullptr; }
public:
T& operator()( std::size_t x, std::size_t y )
{
// Add bounds-checking here depending on your use-case
// by throwing a std::out_of_range if x/y are outside
// of the valid domain.
return m_data[x + y * m_width];
}
const T& operator()( std::size_t x, std::size_t y ) const
{
return m_data[x + y * m_width];
}
private:
std::size_t m_height;
std::size_t m_width;
T* m_data;
};
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>>
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;
}