I have to create an array of array named m2DArray. It has 2 rows and 5 cols i;e a size of [2][5].
The array can be float** or double** which is known to me only at runtime.
Since I do not know the type at compile time, I initialize it in my header files as
void **m2DArray;
Then I create a template function:
template <typename SampleType>
void MyClass::initiliaze2DArray(SampleType** m2DArrayTyped)
{
m2DArray = new SampleType* [2]; //2 rows
int32 sizeOfOneCol = 5 * sizeof(SampleType); // 5 cols
for (int32 row = 0; row < 2; row++)
{
m2DArray[row] = new SampleType [sizeOfOneColumn];
memset(m2DArray[row], 0, sizeOfOneCol);
}
}
Then at runtime I decide between float** or double** based on some logic in the class and accordingly try to initalize the 2d array.
if (somelogictellsfloat){
float **mArrayFloat;
initiliaze2DArray(mArrayFloat);
}
else {
double **mArrayDouble;
initiliaze2DArray(mArrayDouble);
}
However, when trying to initialize this 2d array, I am not able to convert the void** to either float** or double** in my template function.
I get the following error:
error: invalid conversion from ‘double**’ to ‘void**’ in line m2DArray = new SampleType* [2];
My Question:
How do I cast **m2DArray from void ** to float ** or double ** ? Or is there a better way to create this 2d array at runtime.
You have some misunderstandings here. Most important: void** is NOT a generic pointer. The only generic pointer is void*. So, your type void** can hold the address of a generic void*. This you need to understand.
So, regardless, how many dimensions your array would have, you could assign it to a void*. And later, it is your responsibility to cast it to your needed type. See:
// Create a 5 dimensional array
char***** dimension5 = static_cast<char*****>( malloc(200));
// Assign it to a generic pointer
void* generic = dimension5;
// Get the address of the generic pointer
void** addressOfGeneric = &generic;
// Now dereference the address of the generic pointer to get back the generic pointer
// and cast it to our original type
char***** dimension5Later = static_cast<char*****>(*addressOfGeneric);
// Do something with the array
dimension5Later[0][0][0][0][0] = 'H';
But, of course we would never do that. In C++ we should never use raw pointers for owned memory. We should try to avoid raw pointers at all and work with smart pointers. We must not use malloc and we should not even use new and instead some make_unique-function.
I wonder, if you need that at all. Because you should use std::vector instead.
Please see the following:
// The dimension of our 2d vector
constexpr size_t NumberOfRows = 2U;
constexpr size_t NumberOfColumns = 5U;
bool somelogictellsfloat{ true };
// Depending on what to create
if (somelogictellsfloat) {
// Create and initialize a 2d vector for floats
std::vector<std::vector<float>> mArrayFloat(NumberOfRows, std::vector<float>(NumberOfColumns, 0.0));
}
else {
// Create and initialize a 2d vector for doubles
std::vector<std::vector<double>> mArrayDouble(NumberOfRows, std::vector<double>(NumberOfColumns, 0.0));
}
But what you really want, is to use the abstract factory pattern. If you do not know, the please read about this.
By the way. I made for your original code a minimum reproducable example. This you should always do in questions on SO.
I fixed some bugs and made it compilable. But please do not use
#include <cstring>
#include < cstdlib >
#include <vector>
struct MyClass {
void** m2DArray; // Address of a generic pointer
void* md;
float** mArrayFloat;
double** mArrayDouble;
using int32 = int;
template <typename SampleType>
void initiliaze2DArray(SampleType** m2DArrayTyped)
{
m2DArrayTyped = new SampleType * [2]; //2 rows
int32 sizeOfOneCol = 5 * sizeof(SampleType); // 5 cols
for (int32 row = 0; row < 2; row++)
{
m2DArrayTyped[row] = new SampleType[5];
memset(m2DArrayTyped[row], 0, sizeOfOneCol);
}
md = m2DArrayTyped; // md is now a generic pointer
m2DArray = &md; // and m2DArray is the address of that generic pointer
}
// Test function
void test(bool doFloatAndNotDouble) {
if (doFloatAndNotDouble) {
initiliaze2DArray(mArrayFloat);
}
else {
initiliaze2DArray(mArrayDouble);
}
}
};
// Driver code
int main() {
MyClass mc{};
mc.test(true);
mc.test(false);
return 0;
}
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;
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>>
const int ADJ_MATRIX[VERTEX_NUM][VERTEX_NUM]={
{0,1,1,0,0,0,0,0},
{1,0,0,1,1,0,0,0},
{1,0,0,0,0,1,1,0},
{0,1,0,0,0,0,0,1},
{0,1,0,0,0,0,0,1},
{0,0,1,0,0,0,1,0},
{0,0,1,0,0,1,0,0},
{0,0,0,1,1,0,0,0}
};
typedef struct {
int vertex;
int matrix[VERTEX_NUM][VERTEX_NUM];
int vNum;
int eNum;
}Graph;
void buildGraph(Graph *graph){
graph->vNum = VERTEX_NUM;
graph->eNum = EDGE_NUM;
graph->matrix = ADJ_MATRIX;
}
The error occurs in this sentence:
graph->matrix = ADJ_MATRIX;
I am new to c++. please tell me why this problem occur and how to solve it?
I want to assign ADJ_MATRIX to the matrix in struct.
As was said, you can't assign arrays in C++. This is due to the compiler being a meanie, because the compiler can. It just won't let you do it...
... unless you trick it ;)
template <typename T, int N>
struct square_matrix {
T data[N][N];
};
square_matrix<int, 10> a;
square_matrix<int, 10> b;
a = b; // fine, and actually assigns the .data arrays
a.data = b.data; // not allowed, compiler won't let you assign arrays
The catch? Now the code needs some little things:
const square_matrix<int, VERTEX_NUM> ADJ_MATRIX={{
// blah blah
}}; // extra set of braces
typedef struct {
int vertex;
square_matrix<int, VERTEX_NUM> matrix;
int vNum;
int eNum;
}Graph;
void buildGraph(Graph *graph){
graph->vNum = VERTEX_NUM;
graph->eNum = EDGE_NUM;
graph->matrix = ADJ_MATRIX; // no change
}
And to access the cells, now we need to use graph->matrix.data[1][2]. This can be mitigated by overloading operator[] or operator() for square_matrix. However, this is now getting terribly close to the new std::array class, or the Boost equivalent boost::array, so it might be wise to consider those instead.
Unfortunately (or maybe fortunately, who knows...) you can't just assign one array to another in C++.
If you want to copy an array, you will need to either copy each of it's elements into a new array one by one, or use the memcpy() function:
for( int i = 0; i < VERTEX_NUM; i++ )
for( int j = 0; j < VERTEX_NUM; j++ )
graph->matrix[i][j] = ADJ_MATRIX[i][j];
or
memcpy( graph->matrix, ADJ_MATRIX, VERTEX_NUM * VERTEX_NUM * sizeof(int) );
Arrays are not assignable. You can use memcpy:
memcpy(graph->matrix, ADJ_MATRIX, sizeof(graph->matrix));
You cannot assign an array to another array. You will need to copy the elements from the source to the destination index by index, or use memcpy to copy the data. Array assignment like this is not allowed
You are trying to assign your variable address of a constant data,
try using
memcpy(graph->matrix,ADJ_MATRIX,sizeof(ADJ_MATRIX));//using sizeof(graph->matrix) is safer.
You can't use an array in assignments. You may use cycles or memcpy instead
memcpy(graph->matrix, ADJ_MATRIX, VERTEX_NUM * VERTEX_NUM * sizeof(int));
or
for(int i = 0; i < VERTEX_NUM; ++i){
for(int j = 0; j < VERTEX_NUM; ++j){
graph->matrix[i][j] = ADJ_MATRIX[i][j];
}
}
The error is thrown, because int matrix[VERTEX_NUM][VERTEX_NUM] in a structure definition means that each structure will have a 2D array of integers of the predefined size and matrix is going to be pointing to its first element. The thing is that matrix cannot be assigned to an arbitrary address, because it's a const pointer i.e. its value (the address it's pointing to) cannot change.
You have 2 options here: you can either use memcpy or some stl algorithms to copy the ADJ_MATRIX into matrix directly or you can declare matrix as a pointer and do the assignment that is currently produces an error.
The latter can be done in the following way:
typedef struct {
int vertex;
const int (*matrix)[VERTEX_NUM];
int vNum;
int eNum;
}Graph;
Thus you can do graph->matrix = ADJ_MATRIX assignment, but you won't be able to modify the individual items in matrix due to constness. This means, graph->matrix[0][1] = 3; is not allowed, while you can read the elements freely.
salute..
I am learning dynamic allocations for multidimensional arrays in a book and I found some ways for that, And now haven't problem in it.
But the author of the book shows us a way, but it doesn't work correctly. It is this:
pbeans = new double [3][4]; // Allocate memory for a 3x4 array
And this is the error:
error C2440: '=' : cannot convert from 'int (*)[4]' to 'int *'
how should i define pbeans ( if this type of coding is legal)?
and what is the problem exactly?
Regards.
This is covered in my FAQ on arrays:
double (*pbeans)[4];
pbeans = new double[3][4];
// ...
delete[] pbeans;
For the "C declarator impaired", you could make that more readable with a typedef:
typedef double row[4];
row *pbeans;
pbeans = new row[3];
// ...
delete[] pbeans;
But in C++, we prefer RAII containers over raw pointers:
#include <vector>
#include <array>
std::vector<std::array<double, 4> > beans(3);
Note the complete absence of delete[] which makes this solution exception-safe.
You need to allocate each dimension of the array separately:
double **pbeans = new double*[3];
for (int i = 0; i < 3; ++i) {
pbeans[i] = new double[4];
}
Here is a way to do it that allocates the memory contiguously on the heap:
typedef double MyGrid[3][4];
int main(int argc, char* argv[])
{
MyGrid& x = *(reinterpret_cast<Grid*>(new double[12]));
...
x[1][2] = 0.3333;
...
delete[] &x;
return 0;
}
Which you could easily turn into a more generic solution:
template<typename T, int x, int y>
struct Array2D
{
typedef T CArrayType[x][y];
typedef CArrayType& RefType;
static CArrayType& New()
{
return *(reinterpret_cast<CArrayType*>(new T[x * y]));
}
static void Delete(RefType x)
{
delete[] &x;
}
};
typedef Array2D<double, 3, 4> MyGrid;// define your 2d array with 3 rows / 4 columns.
int main(int argc, char* argv[])
{
MyGrid::RefType j = MyGrid::New();
...
j[1][2] = 0.3333;
...
MyGrid::Delete(j);
return 0;
}
The idea is to just generate the elements in 1D (x*y), and cast it to a 2D array. But since array types are value types, you need to deal in pointers-to-arrays. Using a reference makes it almost transparent.
Boost probably has something like this but I don't know boost well enough to say...
I am trying to return an array Data Member from one smaller 2D Array Object, and trying to insert the array into a larger 2D array object. But when attempting this, I came into two problems.
First problem is that I want to return the name of the 2D array, but I do not know how to properly syntax to return 2D Array name.
This is what my 2D Array data member looks like
private:
int pieceArray[4][4];
// 2D Smaller Array
and I want to return this array into a function, but this one causes a compiler error:
int Piece::returnPiece()
{
return pieceArray; //not vaild
// return the 2D array name
}
I tired using this return type and it worked:
int Piece::returnPiece()
{
return pieceArray[4][4];
}
But I am unsure if this is what I want, as I want to return the array and all of it's content.
The other problem is the InsertArray() function, where I would put the returnPiece() function in the InsertArray()'s argument.
The problem with the InsertArray() is the argument, heres the code for it:
void Grid::InsertArray( int arr[4][4] ) //Compiler accepts, but does not work
{
for(int i = 0; i < x_ROWS ; ++i)
{
for (int j = 0; j < y_COLUMNS ; ++j)
{
squares[i][j] = arr[i][j];
}
}
}
The problem with this is that it does not accept my returnPiece(), and if i remove the "[4][4]", my compiler does not accept.
Mostly all these are syntax errors, but how do I solve these problems?
Returning the whole pieceArray in returnPiece()
The correct syntax for the argument in InsertArray()
The argument of InsertArray() accepting the returnPiece()
These 3 are the major problems that I need help with, and had the same problem when I attempt to use the pointer pointer method. Does anyone know how to solve these 3 problems?
When passing your array around, you have to decide whether or not you want to make a copy of the array, or if you just want to return a pointer to the array. For returning arrays, you can't (easily) return a copy - you can only return a pointer (or reference in C++). For example:
// Piece::returnPiece is a function taking no arguments and returning a pointer to a
// 4x4 array of integers
int (*Piece::returnPiece(void))[4][4]
{
// return pointer to the array
return &pieceArray;
}
To use it, call it like so:
int (*arrayPtr)[4][4] = myPiece->returnPiece();
int cell = (*arrayPtr)[i][j]; // cell now stores the contents of the (i,j)th element
Note the similarity between the type declaration and using it - the parentheses, dereferencing operator *, and brackets are in the same places.
Your declaration for Grid::InsertArray is correct - it takes one argument, which is a 4x4 array of integers. This is call-by-value: whenever you call it, you make a copy of your 4x4 array, so any modification you make are not reflected in the array passed in. If you instead wanted to use call-by-reference, you could pass a pointer to an array instead:
// InsertArray takes one argument which is a pointer to a 4x4 array of integers
void Grid::InsertArray(int (*arr)[4][4])
{
for(int i = 0; i < x_ROWS; i++)
{
for(int j = 0; j < y_COLUMNS ; j++)
squares[i][j] = (*arr)[i][j];
}
}
These type declarations with pointers to multidimensional arrays can get really confusing fast. I recommend making a typedef for it like so:
// Declare IntArray4x4Ptr to be a pointer to a 4x4 array of ints
typedef int (*IntArray4x4Ptr)[4][4];
Then you can declare your functions much more readable:
IntArray4x4Ptr Piece::returnPiece(void) { ... }
void Grid::InsertArray(IntArray4x4Ptr arr) { ... }
You can also use the cdecl program to help decipher complicated C/C++ types.
It seems like you need to read up more on pointers in C++ and on pass by reference vs. pass by value.
Your returnPiece method is defined as returning the value of a single cell. Given the index (e.g., [4][4]) you return a copy of the contents of that cell, so you won't be able to change it, or more correctly, changing it would change the copy.
I'm sure someone will give you the correct syntax, but I would really recommend learning this stuff since otherwise you may use the code that you do get incorrectly.
Here is how I would do it:
class Array {
public:
Array() {
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
(*this)(i, j) = 0;
}
}
}
int &operator()(int i, int j)
{
return pieceArray[i][j];
}
private:
int pieceArray[4][4];
};
You can then do something like:
Array x; // create 4x4 array
x(1, 2) = 3; // modify element
Trouble with Adam Rosenfield's arrayPtr in that Piece::pieceArray can change out from under you. (Copy-by-reference vs Copy-by-value.)
Copy-by-value is inefficient. But if you really want to do it, just cheat:
struct FOO { int piece [4][4]; };
FOO Piece::returnPiece()
{
FOO f;
memcpy( f.piece, pieceArray, sizeof(pieceArray) );
return f;
}
void Grid::InsertArray( const FOO & theFoo )
{
// use theFoo.piece[i][j]
}
Of course, a better, more Object-Oriented solution, would be to have returnPiece() create and return a Piece or Array object. (As Juan suggested...)