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
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.
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++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.
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;
}
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.