Reputation: 1434
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?
Upvotes: 1
Views: 168
Reputation: 7207
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] = #
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;
}
Upvotes: 0
Reputation: 275585
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.
Upvotes: 2
Reputation: 1514
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];
Upvotes: 1
Reputation: 1
void *ptr;
uint64_t test;
ptr = phys_to_virt(physAddr);
test = *(uint64_t*)ptr;
Upvotes: -2