How to static_cast raw pointer to pointer-to-fixed-array - c++

I am having trouble with a function that takes a pointer to a fixed array. I have a simple pointer and the compiler will not allow me to static_cast it to the pointer-to-array type.
Here's some example code:
int main()
{
typedef int (*Arr3)[3];
int a[3] = {1,2,3};
int* p = &a[0];
Arr3 b = static_cast<Arr3>(p);
}
Error message:
prog.cpp:11:10: error: static_cast from 'int *' to 'Arr3' (aka 'int (*)[3]') is not allowed
Arr3 b = static_cast<Arr3>(p);
^~~~~~~~~~~~~~~~~~~~
1 error generated.
I am pretty sure I could use a reinterpret_cast, but is that really my only option here? Or am I missing something?

You can't exactly static_cast here, but there is a trick that’s more type-safe than reinterpret_cast:
#include <iostream>
using std::cout;
typedef int (*arr3p)[3];
typedef int arr3[3];
inline arr3& to_arr3(arr3 p)
{
return *(arr3p)(p);
}
inline arr3p to_arr3p(arr3 p)
{
return (arr3p)(p);
}
int main() {
arr3 a = {1, 2, 3};
int *p = &a[0];
arr3p foo = &to_arr3(p);
cout << (*foo)[0] << ", ";
arr3p bar = to_arr3p(p);
cout << (*bar)[1] << ", ";
arr3& baz = to_arr3(p);
cout << baz[2] << std::endl;
return 0;
}

I believe your cast is incorrect
Arr3 b = static_cast<Arr3>(p);
should be
Arr3 b = static_cast<Arr3>(&a);
In fact, the cast is unnecessary. Simply
Arr3 b = &a;
will do.

One-dimension array is compatible with pointer, but that's not true for multi-dimension array. For example,
int *p = (int*)1;
int (*s)[3] = (int (*)[3])2;
printf("%d,%d\n", sizeof(int*), sizeof(int (*)[3]));
printf("%d,%d\n", ++p,++s);
The output is:
8,8
5,14
They are both pointer type, so their size is 8 bytes int 64-bit machine.++s, this array pointer will advance 3 elements, but ++p, p will only advance 1 element. When we declare pointer array, we must specify size in every dimension except 1th dimension. The compiler needs to known that information to compute pointer arithmetic operation.

Related

Array and pointer

I am wondering how come the # number1 code not working
as I am trying to use increment operator to display the next following element in the array.
But the # number2 code works , and it was the same code but in a function
//# number 1 code
using namespace std;
int main(){
int arrays[5]={2,4,6,8,10};
for(int x=0;x<5;x++){
cout<<*arrays<<endl;
arrays++; //error: lvalue required as increment operand
}
}
//# number 2 code
using namespace std;
void display(int *arr,int size){
for(int x=0; x<5;x++){
cout<<*arr<<endl;
arr++; //This time no error!!!
}
}
int main(){
int arrays[5]={2,4,6,8,10};
display(arrays,5);
return 0;
}
That's because you cannot change the address of an array.
In # number 1 code when you do array++, you are actually trying to operate directly on the variable which is storing the base address of the array.
What you can try instead is something like below:
int *p = array;
p++;
Whereas in the case when you are calling a function passing the array's base address # number 2, you are implicitly doing what has been shown in the above code snippet.
This is a common problem for beginners. Arrays are not pointers!. Arrays are implicitly converted to pointers. That is where the confusion lies. Consider this:
int array[] = {1, 2, 3};
std::cout << *array << '\n';
What do you think is happening when we do *array. Does it really make sense to dereference an array? The array is being implicitly converted to a int * and then dereferenced. What about this:
int array[] = {1, 2, 3};
array++;
std::cout << *array << '\n';
This doesn't compile (as you found out for yourself). In this statement array++, the array is not implicitly converted to a pointer.
Arrays are converted to pointers when you pass them to functions that accept pointers. That makes it possible to do this:
int array[3] = {1, 2, 3};
display(array, 3);
An array is a sequence of objects stored on the stack. You access this sequence of objects as a pointer to the first object. Both arrays and pointers can be subscripted. They share many similarities but are fundamentally different.
To make your first example compile, subscript the array with x:
for (int x = 0; x < 5; x++) {
std::cout << arrays[x] << '\n';
}
Use :
int *arr = arrays;
arr++;
in code #1. It will work. This is because you need first to create a pointer to the base of the array which you can increment as in the second code, you have the pointer in the form of the passed argument to the function.

Is array variable a reference in C++?

I am just learning C++ and a little confused about arrays and references. I wrote the following program:
void printArray(int arr[]) {
cout << arr[0] << arr[1] << arr[2] << endl;
}
int main() {
int arr[3] = {5, 7, 9};
int *aPtr = &arr[0];
cout << aPtr[0] << aPtr[1] << aPtr[2] << endl;
int *bPtr = arr;
cout << bPtr[0] << bPtr[1] << bPtr[2] << endl;
printArray(arr);
}
The output is :
579
579
579
And I have two questions:
Is array in C++ a reference? I mean, can I state that i = &i[0]?
If answer to the first question is yes, can I say that as array is reference we don't need to use & in arguments of the function printArray. I mean, we don't declare the function this way printArray(int &arr[])?
No, an array is not a reference in C++. It is an array, the length of which forms part of the type (so for example the type of int[3] is not the same as that of int[42]).
What can be confusing is that C++ inherits from C the strange features that
array function parameters have their type "adjusted" to pointer
array names can "decay" to pointers very easily. That makes it possible to assign an array to a pointer.
Point 1 above means that these two function declarations are completely equivalent:
// two ways do declaring the same function
void foo(int a[42]);
void foo(int* a);
and point 2 means you can call the function passing it an array:
int a[3] = {};
int b[100] = {};
foo(a);
foo(b);
and other funny stuff, for example, the type of expression +a being int*.

C & C++: What is the difference between pointer-to and address-of array?

C++11 code:
int a[3];
auto b = a; // b is of type int*
auto c = &a; // c is of type int(*)[1]
C code:
int a[3];
int *b = a;
int (*c)[3] = &a;
The values of b and c are the same.
What is the difference between b and c? Why are they not the same type?
UPDATE: I changed the array size from 1 to 3.
The sizeof operator should behave differently, for one, especially if you change the declaration of a to a different number of integers, such as int a[7]:
int main()
{
int a[7];
auto b = a;
auto c = &a;
std::cout << sizeof(*b) << std::endl; // outputs sizeof(int)
std::cout << sizeof(*c) << std::endl; // outputs sizeof(int[7])
return 0;
}
For me, this prints:
4
28
That's because the two pointers are very different types. One is a pointer to integer, and the other is a pointer to an array of 7 integers.
The second one really does have pointer-to-array type. If you dereference it, sure, it'll decay to a pointer in most cases, but it's not actually a pointer to pointer to int. The first one is pointer-to-int because the decay happened at the assignment.
Other places it would show up is if you really did have two variables of pointer-to-array type, and tried to assign one to the other:
int main()
{
int a[7];
int b[9];
auto aa = &a;
auto bb = &b;
aa = bb;
return 0;
}
This earns me the error message:
xx.cpp: In function ‘int main()’:
xx.cpp:14:8: error: cannot convert ‘int (*)[9]’ to ‘int (*)[7]’ in assignment
aa = bb;
This example, however, works, because dereferencing bb allows it to decay to pointer-to-int:
int main()
{
int a;
int b[9];
auto aa = &a;
auto bb = &b;
aa = *bb;
return 0;
}
Note that the decay doesn't happen on the left side of an assignment. This doesn't work:
int main()
{
int a[7];
int b[9];
auto aa = &a;
auto bb = &b;
*aa = *bb;
return 0;
}
It earns you this:
xx2.cpp: In function ‘int main()’:
xx2.cpp:14:9: error: incompatible types in assignment of ‘int [9]’ to ‘int [7]’
*aa = *bb;
The identity of any object in C++ is determined by the pair of its type and its address.
There are two distinct objects with the same address in your example: The array itself, and the first element of the array. The first has type int[1], the second has type int. Two distinct objects can have the same address if one is a subobject of the other, as is the case for array elements, class members, and class base subobjects.
Your example would be clearer if you wrote:
int a[5];
int (*ptr_to_array)[5] = &a;
int * ptr_to_array_element = &a[0];
But you have taken advantage of the fact that the id-expression a for the array decays to a pointer to the array's first element, so a has the same value as &a[0] in your context.
Consider this example:
#include<stdio.h>
int main()
{
int myArray[10][10][10][10]; //A 4 Dimentional array;
//THESE WILL ALL PRINT THE SAME VALUE
printf("%d, %d, %d, %d, %d\n",
myArray,
myArray[0],
myArray[0][0],
myArray[0][0][0],
&myArray[0][0][0][0]
);
//NOW SEE WHAT VALUES YOU GET AFTER ADDING 1 TO EACH OF THESE POINTERS
printf("%d, %d, %d, %d, %d\n",
myArray+1,
myArray[0]+1,
myArray[0][0]+1,
myArray[0][0][0]+1,
&myArray[0][0][0][0]+1
);
}
You will find that all the 5 values printed in first case are all equal. Because they point to the same initial location.
But just when you increment them by 1 you see that different pointers now jump (point) to different locations. This is because myArray[0][0][0] + 1 will jump by 10 integer values that is 40 bytes, while myArray[0][0] + 1 will jump by 100 integer values i.e by 400 bytes. Similarly myArray[0] + 1 jumps by 1000 integer values or 4000 bytes.
So the values depend on what level of pointer you are referring to.
But now, if I use pointers to refer all of them:
#include<stdio.h>
int main()
{
int myArray[10][10][10][10]; //A 4 Dimentional array;
int * ptr1 = myArray[10][10][10];
int ** ptr2 = myArray[10][10];
int *** ptr3 = myArray[10];
int **** ptr4 = myArray;
//THESE WILL ALL PRINT THE SAME VALUE
printf("%u, %u, %u, %u\n", ptr1, ptr2, ptr3, ptr4);
//THESE ALSO PRINT SAME VALUES!!
printf("%d, %d, %d, %d\n",ptr1+1,ptr2+1,ptr3+1,ptr4+1);
}
So you see, different levels of pointer variables do not behave the way the array variable does.

reference to an array in c++

Question is make an array of 10 integers that's fine
int array[10];
Now question is
how to make a reference to an array which I have declared above ?
I tried this
int &ra = a;
But it's giving me error...
Please provide me details about this error and how to make reference of an array.
int (&ra)[10] = a;
Alternatively, you can use a typedef to separate this into the type for "array of 10 ints" and having a reference there-to, as in:
typedef int int10[10];
int10& my_ref = a;
The problem with your int &ra = a; is that it tells the compiler to create a reference of type int that refers to an array of 10 ints... they're just not the same thing. Consider that sizeof(int) is a tenth of the size of an array of ten ints - they occupy different amounts of memory. What you've asked for with the reference's type could be satisfied by a particular integer, as in int& ra = a[0];.
I appreciate it's a bit confusing that int* p = a; is allowed - for compatibility with the less type-safe C, pointers can be used to access single elements or arrays, despite not preserving any information about the array size. That's one reason to prefer references - they add a little safety and functionality over pointers.
For examples of increased functionality, you can take sizeof my_ref and get the number of bytes in the int array (10 * sizeof(int)), whereas sizeof p would give you the size of the pointer (sizeof(int*)) and sizeof *p == sizeof(int). And you can have code like this that "captures" the array dimension for use within a function:
template <int N>
void f(int (&x)[N])
{
std::cout << "I know this array has " << N << " elements\n";
}
The reference to array will have type int (&a)[10].
int array[10];
int (&a)[10] = array;
Sometimes it might be useful to simplify things a little bit using typedef
typedef int (&ArrayRef)[10];
...
ArrayRef a = array;
This is a reference to an array of of ints of size 10:
int (&ra)[10];
so
int (&ra)[10] = a;
You can typedef the array type (the type should not be incomplete) as follow:
#define LEN 10
typedef int (array)[LEN];
int main(void)
{
array arr = {1, 2, 3, 4, 5}; //define int arr[10] = {1, 2, 3, 4, 5};
array arr2; //declare int arr[10];
array *arrptr = &arr; // pointer to array: int (*arrptr)[10] = &arr;
array &&arrvef; // declare rvalue reference to array of 10 ints
array &ref = arr; // define reference to arr: int (&ref)[10] = arr;
}

Array as array[n] and as pointer array*

What is the difference when array is declared as array[n] or as pointer array* according to example below? I guess that for example both 'a' and 'c' point at the first element of array, but they behave different.
#include <iostream>
int main() {
int a[3] = {1};
int b[5];
std::cout << *a << std::endl; //prints 1 - ok
//a = b; //error during compilation
int* c = new int[3];
c[0] = 2;
int* d = new int[5];
std::cout << *c << std::endl; //prints 2 - ok
c = d; //works ok!
return 0;
}
Long story short - they are essentially the same, but ever so slightly different.
From what I've gathered from http://c-faq.com/aryptr/aryptr2.html , whilst they can both act as a pointer to the front of an array, when you declare an array as
int a[3];
you are essentially binding the size of '3' to your variable a, along with the fact it's an array. Hence, when you try to assign b, of size 5 to a, you get a compilation error.
In contrast, when you write
int * a;
You are merely saying 'this is a pointer that may point to an array', with no promise on the size.
Subtle, isn't it?
The difference between the following two lines:
int g[10];
and
int* h = new int[10];
is that the second is dynamically-allocated, whereas the first is statically-allocated.
For most purposes, they are identical, but where in memory they end up living is different.