I am having problems understanding how to assign to the Test array as shown below:
int (*&Test)[10] = Parray; Test is a reference to a pointer to an array of ten ints.
The error I get is as follows:
error: incompatible types in assignment of 'int*' to 'int [10]'|.
I have done my research without understanding this completely. I'm reading C++ Primer 5th edition.
int main() {
int arr[10];
int n = 5;
int *ptr1 = &n;
int arr2[10];
int *ptrs[10]; // ptrs is an array of ten pointers
// Parray points to an array of ten ints
int (*Parray)[10] = &arr;
// arrRef refers to an array of ten ints
int (&arrRef)[10] = arr2;
// Test is a reference to a pointer to an array of ten ints.
int (*&Test)[10] = Parray;
// How can I assign to Test[0..1..2..etc]?
// This is what I am trying to do:
Test[0] = ptr1; // Error here
return 0;
}
How can I assign to Test[0] etc.?
Use the followi ng expression statement
Test[0][0] = *ptr1;
The type of expression Test[0] is int [10]. So Test[0][0] will have type int and *ptr1 has type int Of course ptr1 shall have a valid value that may be dereferenced.
It should be:
(*Test)[0] = 3;
(*Test)[1] = 5;
etc. Alternatively you can write Test[0][0] = 3; Test[0][1] = 5; however I think that is less clear.
Test is a reference to the same type as Parray. Dereferencing this gives an array of 10 int, which you can then use array syntax on.
Related
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;
}
In C++ following is valid
int *p = new int[3];
*p=0;
*(++p)=1;
Also following is valid
int j[] = { 0, 1, 2};
*j = 3;
Given, *j =3 works, Why is following invalid
*(++j)=4;//invalid.. lvalue required as increment operand
In an expression like this
*(++j)=4;//invalid.. lvalue required as increment operand
j which is an array int[3] "decays" to a pointer to the first element of that array. That pointer is an rvalue, and can't be assigned, therefore you can't do things like *(++j).
In your other example p is a pointer which is non const and can be assigned:
int *p = new int[3];
*p=0;
*(++p)=1;
The behavior you obtain with the rvalue is similar to what would happen with a const pointer:
int const *p = new int[3];
*p=0;
*(++p)=1;
Arrays and pointers are similar, but this is one place where they are not.
If you want to iterate over an array, use a separate pointer variable:
int j[] = { 0, 1, 2};
int* jp = j;
jp then points to the first element of j. Then:
*(++jp) = 4;
will work.
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.
I have a question.
I created a correctly initialized integer pointer
int * p
and a correctly initialized integer array
int * array1 = new int[]
Which of the following is legal code?
p = array1;
array1 = p;
Or are both correct?
is this possible as well
p[0] since, to my pointer arithmetic knowledge, it doesn't add anything.
All in c++
If the question is trying to get at pointers versus arrays, they are not always compatible. This is hidden in the presented code because the array is immediately converted to a pointer.
int* array1 = new int[5]; // Legal, initialising pointer with heap allocated array
int array2[5] = {0}; // Declaring array directly on the stack and initalising with zeros
int *p = 0; // Declaring pointer and initialising to numm
p = array2; // Legal, assigning array to pointer
p = array1; // Legal, assigning pointer to pointer
array1 = p; // Legal, assigning pointer to pointer
array2 = p; // ILLEGAL, assigning pointer to array
Here array2 has an array type and cannot be used to store a pointer. Actually, the array cannot be reassigned at all, as it is not an l-value.
int array3[5] = {0}; // Declaring array directly on the stack and initalising with zeroes
array3 = array2; // ILLEGAL, array not an l-value
The array has a fixed address and reassiging it would be similar to trying to write:
int i = 0;
&i = p;
[Hopefully, trying to reassign the location of a variable is obvious nonsense.]
Both are legal.
The first, "p = array1", will cause your correctly initialized integer pointer to be leaked and to point p to the first occurrence of the array that array1 points to.
The second, "array1 = p", will cause the correctly initialized integer array to to be leaked and to point array1 to the single int that p points to.
So I suspect I'm missing something. Could you perhaps post complete code?
If both p and array1 are declared as "int *", as you imply here, then either assignment is legal, by definition.
both are leagal.
passing adresses to eachother. dont knw what u want to do
According to the explanation provided in this site. The first assigned in is correct but the second assignment cannot be considered valid. Please look under the title 'Pointers and arrays'.
You can assign your array variable to pointer variable. So p = array1 is correct.
You can refer this code.
#include <iostream>
using namespace std;
int main ()
{
int numbers[5];
int * p;
p = numbers; *p = 10;
p++; *p = 20;
p = &numbers[2]; *p = 30;
p = numbers + 3; *p = 40;
p = numbers; *(p+4) = 50;
for (int n=0; n<5; n++)
cout << numbers[n] << ", ";
for (int n=0; n<5; n++)
cout << p[n] << ", ";
return 0;
}
If both are pointers then no need to declare pointer as array like int *array1 = new int[].
Both variables are of type pointer to int. So both assignments are legal. The fact that one of the variables is an array doesn't matter in C. Arrays and pointers are the same after initialization.
"I created a correctly initialized integer pointer int * p and a correctly initialized integer array int * array1 = new int[]"
First of all, keeping the syntactical mistakes aside, the terminology is wrong.
int *p; - Here you are just declaring a pointer to hold an integer variable's address. You are not initializing it. Declaration is different from initialization and initialization is different from assignment.
int *array1 = new int[]; - Keeping the error aside, this is not an initialized integer array. array1 is a pointer pointing to an array of integers.
And passing nothing to [] is incorrect. A value needs to be passed that decides number of memory locations to be allocated for holding integer values.
Answering the questions.
Which of the following is legal code?
p = array1;
If, array1 is properly initialized it's correct. p points to the first integer in the array1. Even if it is not properly initialized also, it is correct. In this case, both array and p points to garbage values.
int* array1 = new int[5]; // Notice **5** being passed.
array1 = p;
Infact this operation is useless. Both p and array1 were both pointing to the same location earlier. But this is legally correct.
is this possible as well p[0] ?
Yes, it's correct. p can dereference to 0 to 4 as it's index values. If you just want to p[0], in that case -
int* array1 = new int ; // Notice nothing being passed.