int (*p) [4] ;
Is "p" pointer to array of 4 integers ?? or what ??
and How can I call "new" for this pointer ??
Is "p" pointer to array of 4 integers?
Correct!
How can I call "new" for this pointer?
For example, p = new int[7][4].
int (*p)[4] is, indeed, a pointer to an array of four ints.
You can dynamically allocat an object of type "pointer to array of four int" as follows.
int (**ptr)[4] = new (int (*)[4]);
Note, no space for any ints is allocated; only the pointer itself.
You can allocated an array of 4 ints as follows:
int *ptr = new int[4];
What you can't do (without explicit casting) is assign a pointer to a dynamically allocated array of 4 int to a pointer of type int (*)[4]. Whenever you allocate an array via new, even if you use a typedef, the type of the new expression is a pointer to the first element of the array; the size of the array is not retained in the type of the new expression.
This is because new[] expressions can allocate arrays where the size of the array is chosen at runtime so would not always be possible (or even desirable) to encode the array size into the type of the new expression.
As has been suggested, you can dynamically allocate an array of one array of 4 int. The size of the first array is lost from the type information and what you get is a pointer to the first element of the array (of size 1) of the arrays of four int.
int (*p)[4] = new int[1][4];
Even though it is an array of just 1 (arrays of 4 int), you still need to use delete[] to deallocate p.
delete[] p;
The online CDECL evaluator is a helpful resource for questions like this:
cdecl
C gibberish ↔ English
int (*p)[4];
declare p as pointer to array 4 of int
Related
In C++ we can write:
int arr[] = {20,3,2,0,-10,-7,7,0,1,22};
//Smal Note: Why int *arr = {20,3,2,0,-10,-7,7,0,1,22}; won't work? I learnt I can replace [] with *
but what if I want to allocated arr on heap in one line?
I tried:
int arr[] = new int {20,3,2,0,-10,-7,7,0,1,22};
In function arguments, int[] means "an array of unknown size", and is technically equivalent to int*. (when the pointer is interpreted as a pointer to the first integer in an array).
But in your declaration, int[] means "an array whose size is determined by the initializer", and that is a very well-known size.
new int[] does create an array on the heap, but it returns a pointer to the first element. You might notice a similarity here with function arguments - it's easy to convert from an array to a pointer.
std::vector<int> creates an array on the heap too, but the vector object which manages the array can live anywhere. That's often a lot more convenient.
If you write int arr[] = {20,3,2,0,-10,-7,7,0,1,22}; your arr is usually stored on the stack, just like int a=20, b=3, ...;. In this case, the right-hand side is an initializer, which just tells how int arr[] is initialized.
On the other hand, if you write int *arr = new int[]{20,3,2,0,-10,-7,7,0,1,22}; the array is created on the heap, which can only be accessed via pointers, and the pointer pointing to the array is assigned into int *arr which in turn is on the stack.
So in the context of declaration, int[] and int* are completely different things. But both int[] array and int* array can be accessed using the [] operator, e.g. arr[2] which is synonymous with *(arr+2). And when you use int[] or int* as an argument of a function, they are completely interchangeable.
Is pointer a variable or an address?
Because int** array= new int*[4] is so confusing.
For int** array in this code, the pointer becomes variables to store the pointer addresses, and new int*[4] becomes addresses that will be stored in another pointer.
What am I understanding wrong?
Pointer is a data type, similar to int or char. The data here is a memory address. Pointers are qualified with the types of values expected to be located in the memory at the referred addresses. As other data types, pointers could be used as types for variables, function arguments, array elements etc.
So, int **array is a variable of type int ** which means a pointer to a value of type int * located somewhere in the memory. In turn, int * means a pointer to a value of type int located somewhere in the memory. Or, in short, int ** is a pointer to a pointer to an int.
Expression new int*[4] means allocate in the memory an object of type int *[4] and return a pointer to it. Type int *[4] means an array of four elements of type int * where int *, as we already know, means a point to int value.
So, in the initialization, the types of the left part (int **) and of the right part (int *[]) are different. However, C++ is able to automatically convert arrays into pointers in case the type of array element is the same as the type of the value referred by the pointer. In our case, array element type is int * and the same is the type referred by the pointer. When an array is converted to a pointer, the resulting pointer will refer to the first element of the array.
In this declaration
int** array= new int*[4];
array is a variable that is initialized by the address of the first element of a dynamically allocated array with the element type int *.
If you have an array declared like
T array[N];
where T is some type then a pointer to the first element of the array can be declared like
T *p = array;
If to take into account your array then just T is equal to int *.
Simply put, a pointer is a variable that can store the address of another variable instead of an int or a float or some other value like a "normal" variable.
Like any other variable, the pointer itself also has an address so you can have a pointer to pointer, i.e. a pointer that stores the address of another pointer.
Could somebody explain the difference between these two function declarations below please? As far I know, aDecay() takes a pointer as an argument and if you have an integer int a[5] you can call aDecay(a) or aDecay(&a[0] because an array decays to a pointer.
Now if I want to call pDecay() I have to use pDecay(&a).
How does pDecay force you to use the &.
void aDecay(int *p)
void pDecay(int (*p)[7])
With plain a (or its equal &a[0]) you have a pointer to a single element in the array. A single element is of type int, so a pointer to it must be int*.
If you have a pointer to the actual array, like you get with &a, you no longer have a pointer to a single int element but to the whole array. The type of the array is int[5], and a pointer to it is int(*)[5].
Also note that in neither case you pass the array by value. You pass a pointer by value.
This is not a pointer to function syntax, it's a pointer to array syntax.
In the first example p is a pointer to an array of integers. p[i] is a single int. It cannot be indexed any further.
In the second example p is a pointer to an array of seven integer arrays. p[i] is an array which can be indexed further, i.e. p[i][0] is valid.
Here is an example of using the second approach:
void fill_data(int (*p)[7], size_t n) {
for (size_t i = 0 ; i != n ; i++) {
for (size_t j = 0 ; j != 7 ; j++) {
p[i][j] = (int)(7*i+j);
}
}
}
int main() {
int data[10][7];
fill_data(data, 10);
}
Demo
aDecay takes a pointer to an int.
An array of int can decay to a pointer to the array's first element.
pDecay takes a pointer to an array of seven ints.
An array does not implicitly convert into a pointer to itself.
Passing p will convert the array p to a pointer instead of keeping it as an array (this is called array decay, because the array decays to a pointer).
Passing &p will not convert p to a pointer, because it will convert the pointer to p to a generic pointer, which is not a big deal because it is actually a pointer.
Why we don't want to convert p to a pointer is because arrays are not just pointers. If you think that arrays are just pointers, try to compare sizeof(myArray) with sizeof(myPointer). An array embeds also its size, not only the pointer to the first element.
First of all, you have a misconception in the question: if a is an array, a is always a pointer to that array, i.e. you do pDecay(a) - NOT pDecay(&a). Now, [ ] is a dereferencing operation, so if you say a[5] - you dereference a pointer to a + 5 * bytes in memory occupied by the array's unit. Accordingly, a and &a[0] is exactly the same. a[5] and &(a + 5) is the same.
Answering your question, aDecay(int *p) takes a pointer to integer - nothing asks for an array here. int (*p)[7] is an array of 7 integers and compiler will check that's the case.
How does pDecay force you to use the &.
Because an array doesn't decay to just any pointer. It specifically decays to pointer to first element. The type of pointer to first element of an array of int (i.e. int[n]) is: pointer to int (i.e. int*).
The argument of pDecay is int (*p)[7] which is a pointer to an array of 7 int. An int* is not implicitly convertible to (int (*p)[7]; they are separate, incompatible types. Note that pDecay(&a) won't work either because the type of &a is (int (*p)[5] which is also a different type than (int (*p)[7].
pDecay doesn't force you to use & in general. You could pass an array of arrays, which would then decay to a pointer to first array, which is what pDecay accepts:
int arr[n][7];
pDecay(arr);
Could somebody explain the difference between these two function declarations below please?
int* is a pointer to an int object. int (*p)[7] is a pointer to an int[7] object i.e. an array of 7 int.
int (*arr)[5] means arr is a pointer-to-an-array of 5 integers. Now what exactly is this pointer?
Is it the same if I declare int arr[5] where arr is the pointer to the first element?
Is arr from both the examples are the same? If not, then what exactly is a pointer-to-an-array?
Theory
First off some theory (you can skip to the "Answers" section but I suggest you to read this as well):
int arr[5]
this is an array and "arr" is not the pointer to the first element of the array. Under specific circumstances (i.e. passing them as lvalues to a function) they decay into pointers: you lose the ability of calling sizeof on them.
Under normal circumstances an array is an array and a pointer is a pointer and they're two totally different things.
When dealing with a decayed pointer and the pointer to the array you wrote, they behave exactly the same but there's a caveat: an array of type T can decay into a pointer of type T, but only once (or one level-deep). The newly created decayed type cannot further decay into anything else.
This means that a bidimensional array like
int array1[2][2] = {{0, 1}, {2, 3}};
can't be passed to
void function1(int **a);
because it would imply a two-levels decaying and that's not allowed (you lose how elements of the array are laid out). The followings would instead work:
void function1(int a[][2]);
void function1(int a[2][2]);
In the case of a 1-dimensional array passed as lvalue to a function you can have it decayed into a simple pointer and in that case you can use it as you would with any other pointer.
Answers
Answering your questions:
int (*arr)[5]
this is a pointer to an array and you can think of the "being an array of 5 integers" as being its type, i.e. you can't use it to point to an array of 3 integers.
int arr[5]
this is an array and will always behave as an array except when you pass it as an lvalue
int* ptrToArr = arr;
in that case the array decays (with all the exceptions above I cited) and you get a pointer and you can use it as you want.
And: no, they're not equal otherwise something like this would be allowed
int (*arr)[5]
int* ptrToArr = arr; // NOT ALLOWED
Error cannot convert ‘int (*)[5]’ to ‘int*’ in initialization
they're both pointers but the difference is in their type.
At runtime, a pointer is a "just a pointer" regardless of what it points to, the difference is a semantic one; pointer-to-array conveys a different meaning (to the compiler) compared with pointer-to-element
When dealing with a pointer-to-array, you are pointing to an array of a specified size - and the compiler will ensure that you can only point-to an array of that size.
i.e. this code will compile
int theArray[5];
int (*ptrToArray)[5];
ptrToArray = &theArray; // OK
but this will break:
int anotherArray[10];
int (*ptrToArray)[5];
ptrToArray = &anotherArray; // ERROR!
When dealing with a pointer-to-element, you may point to any object in memory with a matching type. (It doesn't necessarily even need to be in an array; the compiler will not make any assumptions or restrict you in any way)
i.e.
int theArray[5];
int* ptrToElement = &theArray[0]; // OK - Pointer-to element 0
and..
int anotherArray[10];
int* ptrToElement = &anotherArray[0]; // Also OK!
In summary, the data type int* does not imply any knowledge of an array, however the data type int (*)[5] implies an array, which must contain exactly 5 elements.
A pointer to an array is a pointer to an array of a certain type. The type includes the type of the elements, as well as the size. You cannot assign an array of a different type to it:
int (*arr)[5];
int a[5];
arr = &a; // OK
int b[42];
arr = &b; // ERROR: b is not of type int[5].
A pointer to the first element of an array can point to the beginning of any array with the right type of element (in fact, it can point to any element in the array):
int* arr;
int a[5];
arr = &a[0]; // OK
int b[42];
arr = &b[0]; // OK
arr = &b[9]; // OK
Note that in C and C++, arrays decay to pointers to the type of their elements in certain contexts. This is why it is possible to do this:
int* arr;
int a[5];
arr = a; // OK, a decays to int*, points to &a[0]
Here, the type of arr (int*) is not the same as that of a (int[5]), but a decays to an int* pointing to its first element, making the assignment legal.
Pointer to array and pointer to first element of array both are different. In case of int (*arr)[5], arr is pointer to chunk of memory of 5 int. Dereferencing arr will give the entire row. In case of int arr[5], arr decays to pointer to first element. Dereferencing arr will give the first element.
In both cases starting address is same but both the pointers are of different type.
Is it the same if i declare int arr[5] where arr is the pointer to the first element? is arr from both example are same? if not, then what exactly is a pointer to an array?
No. To understand this see the diagram for the function1:
void f(void) {
int matrix[4][2] = { {0,1}, {2,3}, {4,5}, {6,7} };
char s[] = "abc";
int i = 123;
int *p1 = &matrix[0][0];
int (*p2)[2] = &matrix[0];
int (*p3)[4][2] = &matrix;
/* code goes here */
}
All three pointers certainly allow you to locate the 0 in matrix[0][0], and if you convert these pointers to ‘byte addresses’ and print them out with a %p directive in printf(), all three are quite likely to produce the same output (on a typical modern computer). But the int * pointer, p1, points only to a single int, as circled in black. The red pointer, p2, whose type is int (*)[2], points to two ints, and the blue pointer -- the one that points to the entire matrix -- really does point to the entire matrix.
These differences affect the results of both pointer arithmetic and the unary * (indirection) operator. Since p1 points to a single int, p1 + 1 moves forward by a single int. The black circle1 is only as big as one int, and *(p1 + 1) is just the next int, whose value is 1. Likewise, sizeof *p1 is just sizeof(int) (probably 4).
Since p2 points to an entire ‘array 2 of int’, however, p2 + 1 will move forward by one such array. The result would be a pointer pointing to a red circle going around the {2,3} pair. Since the result of an indirection operator is an object, *(p2 + 1) is that entire array object, which may fall under The Rule. If it does fall under The Rule, the object will become instead a pointer to its first element, i.e., the int currently holding 2. If it does not fall under The Rule -- for instance, in sizeof *(p2 + 1), which puts the object in object context -- it will remain the entire array object. This means that sizeof *(p2 + 1) (and sizeof *p2 as well, of course) is sizeof(int[2]) (probably 8).
1 Above content has been taken from More Words about Arrays and Pointers.
The address of the whole array, and the address of the first element, are defined to be the same, since arrays in C++ (and C) have no intrinsic padding besides that of the constituent objects.
However, the types of these pointers are different. Until you perform some kind of typecast, comparing an int * to an int (*)[5] is apples to oranges.
If you declare arr[5], then arr is not a pointer to the first element. It is the array object. You can observe this as sizeof( arr ) will be equal to 5 * sizeof (int). An array object implicitly converts to a pointer to its first element.
A pointer to an array does not implicitly convert to anything, which may be the other cause of your confusion.
If you write int arr[5], you are creating an array of five int on the stack. This takes up size equal to the size of five ints.
If you write int (*arr)[5], you are creating a pointer to an array of five int on the stack. This takes up size equal to the size of a pointer.
If it is not clear from the above, the pointer has separate storage from the array, and can point at anything, but the array name cannot be assigned to point at something else.
See my answer here for more details.
I'm working on a project of which I should store constant multi dimensional arrays.I would like to do it with a pointer which points to multi-dimensional arrays.However, I could'nt succeeded.I write this code but it didn't compiled.
int darray[1][2];
int darray2[2][3];
int (*p)[1][2];
p= new int[2];
p[0] = darray;
p[1] = darray2;
Well, let's go through your code line by line (OK, I'll lump the first two lines together)
int darray[1][2];
int darray2[2][3];
OK, this defines two two-dimensional arrays in exactly the way you (probably) expect. Note that formally, those are actually arrays of arrays of ints. More exactly, darray is of type "array of 1 array of 2 ints each", and darray2 is of type "array of 2 arrays of 3 ints each"
int (*p)[1][2];
This defines a pointer to a two-dimensional array of int, or to the first element of an array of such arrays. That is, the type of p is "pointer to array of 1 array of 2 ints each".
p= new int[2];
Here you are allocating space for two ints (i.e. an one-dimensional array of ints, of length two), and new returns a pointer to the first element of that array, i.e. a pointer to int. You try to assign that pointer to int to p, which is a pointer to array of 1 array of 2 ints each, as mentioned above. This gives a type mismatch and should not compile.
It's not entirely clear what you want at that point, but given that you do assignments to p[0] and p[1] afterward, and given that the return value is assigned to p which is of type int (*)[1][2] the obvious choice would be p = new int[2][1][2];
p[0] = darray;
This again doesn't work, because arrays in C++ are not first-class objects. That is, instead of assigning the value of darray to p[0] as the line would suggest (and p[0] indeed would have the right type for that) the rules of C++ say that the array darray is promoted to a pointer to its first element. That is, what this code actually tries to do is to assign a pointer to the first element of darray (of type int (*)[2]) to p[0] (of type int[1][2]), which of course fails. In C++, arrays are simply not assignable.
p[1] = darray2;
This suffers from the same problem, however note that even if arrays were first-class, assignable objects in C++, this still would be a type mismatch because p[1] is of type int[1][2] while darray2 is of type int[2][3].
Note that you get around most of those limitations (apart from the last one) by just wrapping you array into a class C++11 actually provides a standard class template called std::array for this purpose):
struct array12 { int data[1][2]; };
array12 darray;
array12* p;
p = new array12[2];
p[0] = darray;
With a bit more of programming you could also handle the assignment from larger to smaller arrays (your darray2 case) by copying only part of the data by hand.