Initializing a 2D array with operator new - c++

I am trying to declare a 2D array, where each element in the inner array has type uint64_t*. I want to do this in a single line using new, which should be possible in C++11 or later. I tried this:
uint64_t ***db = new uint64_t*[2][64];
However, this is incorrect:
cannot initialize a variable of type 'uint64_t ***' (aka 'unsigned long long ***') with an rvalue of type 'uint64_t *(*)[64]'
Note that the code works correctly when I replace the type with auto.
What is the correct type for the variable?

An array is not a pointer.
On the left you have a pointer to pointers to pointers to integers.
On the right, you are returning a pointer to array of arrays of pointers to integers.
These types do not match.
Now, in C/C++ pointers and arrays are confusing. This is because arrays decay into pointers at the drop of a hat.
Your three star variable can be used to store a jagged array of pointers.
To make a 2d jagged array, you need to both allocate the array of pointers foe the first dimension, then one or more buffers to store the elements. By far the easiest way to do this is a vector of vectors.
Of for whatever reason you insist on using raw pointers, it looks like:
template<class T>
T*const* make_packed2d( std::size_t x, std::size_t y ){
T* inner = new T[x*y];
T**outer = new T*[x];
for (std::size_t i=0; i!=x;++i){
outer[i]=inner+(i*y);
}
return outer;
}
template<class T>
void free_packed2d(T*const* ptr){
if(!ptr) return;
delete[] ptr[0];
delete[] ptr;
}
or similar.
If your array is not jagged, you can do it in one line, but it does not get stored in a three star variable. In the non jagged case, the size of one of the dimensions gets stored in the type.
This type is not compatible with a pointer pointer pointer.
uint64_t *(*ptr)[64] = new uint64_t*[2][64];
the left is the type of variable that can store the new expression you used. I simply copied it out of the error message, and added the variable name in the appropriate spot.
You'll note that the "64" size is hard coded into the variable type. A "jagged" array in C/C++ is an array of pointers to arrays, while a N dimensional array is an array of arrays, where the sub-arrays are fixed in size.
The advantage of "jagged" is that you don't need to know the sub-dimensions as part of the type. The advantage of the non-jagged is that the memory is contiguous, and you don't need the sub-buffers pointing to the sub-arrays.
My make_packed2d attempts to split the difference; it has a sub-buffer pointing to the sub-arrays, but it makes the actual data contiguous and has the sub-buffer pointing to sub-sections of the sub-arrays.

If you want a pointer to an array on heap, you use a pointer to the first element. This means it's the same type as if you would allocate a single element:
uint64_t* p1 = new uint64_t;
uint64_t* p2 = new uint64_t[2];
You should one the second line only use p and p+1, because p+2 is in this example out of range. This goes for all examples below WITH BRACKETS as well.
If you create a pointer to a multidimensional array, you also use a pointer to the first element, but the notation slightly changes. You don't always need the parentheses, but I left them in to see the patterns clearly:
uint64_t (*p1) = new uint64_t; // Optional parentheses.
uint64_t (*p2) = new uint64_t[2]; // Optional parentheses.
uint64_t (*p3)[3] = new uint64_t[2][3]; // Required parentheses.
uint64_t (*p4)[3][4] = new uint64_t[2][3][4]; // Required parentheses.
As you can see, we need parentheses when there are brackets.
And now with pointers:
uint64_t *(*p1) = new uint64_t*; // Optional parentheses.
uint64_t *(*p2) = new uint64_t*[2]; // Optional parentheses.
uint64_t *(*p3)[3] = new uint64_t*[2][3]; // Required parentheses.
uint64_t *(*p4)[3][4] = new uint64_t*[2][3][4]; // Required parentheses.
And finally, BONUS round:
uint64_t **(*p1) = new uint64_t**; // You can leave out the parentheses.
uint64_t **(*p2) = new uint64_t**[2]; // You can leave out the parentheses.
uint64_t **(*p3)[3] = new uint64_t**[2][3];
uint64_t **(*p4)[3][4] = new uint64_t**[2][3][4];

You can use a typedef to simplify the syntax. Then the answer is similar to this answer:
#include <iostream>
typedef uint64_t* uint64_p;
int main() {
uint64_p** db = new uint64_p*[2];
uint64_t num = 5;
db[0] = new uint64_p[64];
db[1] = new uint64_p[64];
db[0][0] = &num;
std::cout << *db[0][0] << std::endl;
return 0;
}
If you want a contiguous block of pointers, you can do this:
#include <iostream>
typedef uint64_t* uint64_p;
typedef uint64_p uint64_p_array[64];
int main() {
uint64_p_array *arr = new uint64_p_array[2];
uint64_t val = 5;
arr[0][0] = &val;
std::cout << *arr[0][0] << std::endl;
return 0;
}

void *ptr;
uint64_t test;
ptr = phys_to_virt(physAddr);
test = *(uint64_t*)ptr;

Related

Passing pointer of multi-dimensional pointer array to a function

ok so suppose I have a function myFunction. Then in main i have a multi dimensional array of pointers. I want to pass a pointer to this array of pointers into myFunction. How would I do that? I know that If you want to pass an int to my function, one can write the function as
myfunct( int x) { ...}
What would that type of x be if I have to pass a pointer to an array of pointers? Thanks in advance :D
Typically you want to modify the elements of an array rather then the actual pointer. The actual pointer is given by malloc and if you change it, by writing directly to the value, it won't affect the memory allocation (except you might loose the initial pointer...).
This might be what you're looking for in a 2D array.
void myfunct(int** ptr,int items, int array_items)
{
//some code
}
int main(int argc, char *argv[])
{
const auto items = 5;
const auto array_items = 7;
int** multi_dimensional_array = reinterpret_cast<int**>(std::malloc(items * sizeof(int*)));
for (auto i = 0 ;i < items;++i)
{
multi_dimensional_array[i] = static_cast<int*>(std::malloc(sizeof(int) * array_items));
}
myfunct(multi_dimensional_array,items,array_items);
//deallocate
}
Wrap your multidimensional array inside a class. That way you can carry the data and dimensions in one block and passing it around is as simple as moving around any other class.
Remember to observe the Rules of Three, Five, and Zero, whichever best applies to how you store your array inside your class. std::vector is a personal favourite because it allows you to use the Rule of Zero.
For example:
#include <iostream>
#include <vector>
struct unspecified
{
};
template<class TYPE>
class TwoDee{
int rows;
int cols;
std::vector<TYPE> data;
public:
TwoDee(int row, int col):rows(row), cols(col), data(rows*cols)
{
// does nothing. All of the heavy lifting was in the initializer
}
// std::vector eliminates the need for destructor, assignment operators, and copy
//and move constructors. All hail the Rule of Zero!
//add a convenience method for easy access to the vector
TYPE & operator()(size_t row, size_t col)
{
return data[row*cols+col];
}
TYPE operator()(size_t row, size_t col) const
{
return data[row*cols+col];
}
};
void function(TwoDee<unspecified *> & matrix)
{
// does stuff to matrix
}
int main()
{
TwoDee<unspecified *> test(10,10);
function(test);
}
To directly answer your question, typically the type passed will be int * for a vector of int, and int ** for a 2D array of int
void myfunct( int **x)
{
x[2][1] = 25;
return;
}
If for some reason you wanted that to be an array of int pointers instead of int you need an extra *.
void myfunct( int ***x)
{
*(x[2][1]) = 25;
return;
}
Let me first try to interpret the exact type that you want to deal with. I suppose in your main function there is a "multidimensional array" which stores pointers for each element. As an example, let's say you have a 3-dimensional array of pointer to integer type.
Assume that you know the size of the array:
C style array will look like this:
int *a[4][3][2];
that means a is a 4x3x2 array, and each element in the array is a pointer to integer. So overall you now have 24 pointers to integer in total, as can be seen by testing the result of sizeof(a) / sizeof(int*) (the result should be 24). Okay, so far so good. But now I guess what you want is a pointer to the array a mentioned above, say b, so b is defined
int *(*b)[4][3][2] = &a;
Notice that although now b looks intimidating, in the end it is just a pointer which just stores an address, and sizeof(b) / sizeof(int*) gives 1 as the result. (The * inside parenthesis indicates b is pointer type, so b is a pointer to a "multidimensional array" of pointers to integer.)
Now to pass b to myFunction, just give the same type of b as argument type in the declaration:
void myFunction(int *(*x)[4][3][2]) {
// do something
}
And that's it! You can directly use myFunction(b) to invoke this function. Also, you can test that inside myFunction, x is still of the size of one pointer, and *x is of the size of 24 pointers.
*Note that since we are passing a pointer to array type into the function, the array-to-pointer decay does not apply here.
Assume you don't know the size of the array at compile time:
Say you have int N1 = 4, N2 = 3, N3 = 2; and you want to initialize a N1xN2xN3 array of pointer to integer, you cannot directly do that on the stack.
You could initialize use new or malloc as suggested in #Mikhail's answer, but that approach takes nested loops for multidimensional arrays and you need to do nested loops again when freeing the memory. So as #user4581301 suggests, std::vector provides a good wrapper for dynamic size array, which do not need us to free the memory by ourselves. Yeah!
The desired array a can be written this way (still looks kind of ugly, but without explicit loops and bother of freeing memory)
std::vector<std::vector<std::vector<int*>>> a (N1,
std::vector<std::vector<int*>> (N2,
std::vector<int*> (N3)
)
);
Now, b (the pointer to a) can be written as
auto *b = &a;
You can now pass b with
void myFunction(std::vector<std::vector<std::vector<int*>>>* x) {
// do something
}
Notice that the * before x means x is a pointer.

Calculate length of double pointer array

I have a double pointer Array of a structure:
typedef struct Position{
int x;
int y;
} Position;
Position** array = (Position**)malloc(sizeof(Position*)*10); //10 elements
array[0] = (Position*)malloc(sizeof(Position*));
array[0]->x = 10;
array[0]->y = 5;
Can I calculate the length of set array and if so, how?
The normal way for arrays does not work :
int length = sizeof(<array>)/sizeof(<array>[0]);
Once you have dynamically allocated an array, there is no way of finding out the number of elements in it.
I once heard of some hacky way to obtain the size of a memory block, (msize) which would allegedly allow you to infer the size of the data within the block, but I would advice against any such weird tricks, because they are not covered by the standard, they represent compiler-vendor-specific extensions.
So, the only way to know the size of your array is to keep the size of the array around. Declare a struct, put the array and its length in the struct, and use that instead of the naked array.
As you marked the question as C++, I would suggest that you use std::vector, then, after you "allocated some memory" (or requested some memory to allocated by std::vector constructor or by using push_back, or resize), you can simply get the size back using by using std::vector::size.
typedef struct Position{
int x;
int y;
} Position;
std::vector<Position> array(10);
array[0].x = 10;
array[0].y = 5;
size_t size = array.size(); // will be 10
Having only a pointer to some memory block, you cannot defer the size of this memory block. So you cannot defer the number of elements in it.
For arrays of pointers, however, you could infer the number of elements in it under the following conditions:
make sure that every pointer (except the last one) points to a valid object.
for the last pointer in the array, make sure that it is always NULL.
Then you can derive the length by counting until you reach NULL.
Maybe there are some other similar strategies.
Solely from the pointer itself, however, you cannot derive the number of elements in it.
Old question, but in case someone needs it:
#include <stdio.h>
...
int main()
{
char **double_pointer_char;
...
int length_counter = 0;
while(double_pointer_char[length_counter])
length_counter++;
...
return 0;
}

Instantiating a 3D array in C++ using parameters

Sorry if this is a noob question, but I'm currently learning C++. I have a function that takes in several parameters - I would like to use those parameters when creating a 3D int array.
void* testFunction(int countX, int countY, int countZ)
{
const int NX = countX;
const int NY = countY;
const int NZ = countZ;
int* data_out = new int*[NX][NY][NZ];
// The above line throws the error on "NY" - expression must
// have a constant value
}
From various posts I've learned that you must allocate the array first but I guess I'm doing that wrong? How do you properly initialize a multidimensional array. Also, why does the initialization require a pointer?
To explain the error: C++ requires a name of a type in its new operator. A name of a type cannot have runtime dimensions, because all types in C++ are static (determined at compilation time).
For example, this allocates 3 elements of type int[4][5]:
new int[3][4][5];
Another example: this allocates NX elements of type int[4][5]:
new int[NX][4][5];
An incorrect example: this would allocate NX elements of type int[NY][NZ], if C++ had support for "dynamic" types:
new int[NX][NY][NZ];
To allocate a 3-dimensional array, or something that looks like it, you can use std::vector:
std::vector<std::vector<std::vector<int>>> my_3D_array;
... // initialization goes here
my_3D_array[2][2][2] = 222; // whatever you want to do with it
To make the syntax less verbose, and streamline the initialization, use typedef (or here using, which is the same):
using int_1D = std::vector<int>; // this is a 1-dimensional array type
using int_2D = std::vector<int_1D>; // this is a 2-dimensional array type
using int_3D = std::vector<int_2D>; // this is a 3-dimensional array type
int_3D data(NX, int_2D(NY, int_1D(NZ))); // allocate a 3-D array, elements initialized to 0
data[2][2][2] = 222;
If you want to return this array from your function, you should declare it; you cannot just return a void pointer to the data variable. Here is a syntax of a declaration:
using int_1D = std::vector<int>;
using int_2D = std::vector<int_1D>;
using int_3D = std::vector<int_2D>;
int_3D testFunction(int countX, int countY, int countZ)
{
int_3D data(...);
...
return data;
}
That is, instead of using new, just use std::vector<whatever> as if it were any other type.

C++ Syntax - Multidimensional Dynamic Array

I need help understanding the syntax of multidimensional arrays in C++. In the book I'm learning C++ from, the code snippet looks like this:
typedef int* IntArrayPtr;
IntArrayPtr *m = new IntArrayPtr[num_rows];
for(int i = 0; i < rows; i++){
m[i] = new int[num_columns]
}
My question is this: Why is there a star infront of the m? To me when I see
new IntArrayPtr[num_rows];
that's enough information to tell the compiler that it's an array of pointers that point to int. The star just makes it confusing. Is there something I'm missing here?
Keep in mind that what you have when you do new IntArrayPtr[num_rows] is an array of IntArrayPtrs. In C new[], "allocates size bytes of storage, suitably aligned to represent any object of that size, and returns a non-null pointer to the first byte of this block." So new[] is returning you a pointer to the first element of your array.
For example if num_rows is 3 this is what gets allocated in memory:
m --> [IntArrayPtr]
[IntArrayPtr]
[IntArrayPtr]
m being a pointer is what allows you to use the index operator on it: m[1] returns you the second IntArrayPtr in m.
m is the pointer to pointer which handles starting points of columns as a row. Example of this example in c
int **arr=(int**)malloc(num_rows * (sizeof(int*) ) );
for(i=0;i<row;i++)
{
arr[i]=(int*)malloc(sizeof(int)*col_rows);
}
if we use typedef,
typedef int* IntArrayPtr;
IntArrayPtr *arr=(IntArrayPtr*)malloc(num_rows * (sizeof(IntArrayPtr) ) );
for(i=0;i<row;i++)
{
arr[i]=(IntArrayPtr)malloc(sizeof(int)*col_rows);
}
As you see, firstly we create a pointer array to hold pointers of columns. After that we allocate a place for every columns of array and assign starting points of one dimensional column arrays to one dimensional pointer array.

What is ** in C++

I am currently reading some C++ source code, and I came across this:
double **out;
// ... lots of code here
// allocate memory for out
out = new double*[num];
Not entirely sure what it does, or what it means. Is it a pointer... to another pointer?
There is also the following:
double ***weight;
// allocate memory for weight
weight = new double**[numl];
I am quite confused :P, any help is appreciated.
new double*[num] is an array of double pointers i.e. each element of the array is a double*. You can allocate memory for each element using out[i] = new double; Similarly weight is an array of double**. You can allocate the memory for each weight element using new double*[num] (if it is supposed to be an array of double*)
It's a pointer to pointer to double. Or array of pointers to double. Or if every pointer itself allocates array it might be a matrix.
out = new double*[num]; // array of pointers
Now it depents if out[0] is allocated like this:
out[0] = new double; // one double
or like this:
out[0] = new double[num]; // now you've got a matrix
Actually, writing
double*[] out;
is in C/C++ equal to
double** out;
and it means an array of pointers to double. Or a pointer to pointers of double. Because an array is nothing more than just a pointer. So this is in essence a two-dimensional array.
You could as well write
double[][] out;
And likewise, adding another pointer level, will add another dimension to your array.
So
double ***weight;
is actually a pointer to a three-dimensional array.
Basically both of your code fragments allocate array of pointers. For allocation it does not matters to what. Correct declaration is needed only for type checks. Square bracjets should be read separately and means only it is array.
Consider following code as quick example:
#include <stdio.h>
int main()
{
unsigned num = 10;
double **p1, ***p2;
p1 = new double*[num];
p2 = new double**[num];
printf("%d\n", sizeof(p1));
printf("%d\n", sizeof(p2));
delete [] p1;
delete [] p2;
return 0;
}
Yes, both are just pointers. And memory allocated is sizeof(double*) * num.