Advanced Pointer convoluted syntax - c++

I was fidgeting with the pointers thingy.graduated from pointers -> array of pointers -> function pointers -> pointer to pointers..
Here's what i am stuck at...mostly the convoluted syntax.
Lets say i have an array of integers.
int arr[4] = {1,2,3..};
also i have array of pointers
int* ptr[4];
ptr[0] = arr;
here ptr[0] will point to 1
and ptr[1] will point to some other location
This works perfectly !!
Now considering above background i tried this.
char* crr[4] ={"C","C++","C#","F#"};
char** btr[4];
btr[0] = crr;
which works as pointer in oth element of btr is pointing to another pointer element in crr.
Then i tried this.
char* crr[4] ={"C","C++","Java","VBA"};
char** btr[4]= &crr; // Exception: cannot convert char* [4] * to char**[4]
but when i do this it works :O
char* crr[4] ={"C","C++","Java","VBA"};
char* (*btr)[4]= &crr;
i have not understood the last two scenarios. The use of brackets on RHS Pls explain.

char** btr[4]= &crr; // Exception: cannot convert char* [4] * to char**[4]
That's trying to initialise an array (of pointers to pointers) from a pointer, which you can't do. If you wanted to initialise the first element to point to crr (as in your first example), then you'd do
char** btr[4]= {crr};
The last example is declaring a pointer to an array (of pointers), and initialising it from a compatible pointer.
Note that your original array should be of const char *, not char *, since it contains pointers to (constant) string literals.

Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.
When you write
btr[0] = crr;
the expression crr has type "4-element array of char *"; since it is not the operand of a sizeof or & operator, it is converted to type "pointer to char *", or char **. This matches the type of btr[0].
However, when you write
char** btr[4]= &crr;
the expression crr is the operand of the & operator; thus, the type of the expression &crr is "pointer to 4-element array of char *", or char *(*)[4].
The parentheses are necessary because the postfix [] operator has higher precedence than the unary * operator; the expression *a[i] will always be parsed as *(a[i]). Thus,
T *a[N]; // a is an N-element array of pointer to T
T (*a)[N]; // a is a pointer to an N-element array of T
T *(*a)[N]; // a is a pointer to an N-element array of pointer to T
The same is true for pointers and functions:
T *f(); // f is a function returning a pointer to T
T (*f)(); // f is a pointer to a function returning T
T *(*f)(); // f is a pointer to a function returning pointer to T

Let's look at your definitions:
Array of size 4 of char*
char* crr[4] ={"C","C++","Java","VBA"};
Array of size 4 of char**
char** btr[4]
Pointer to an array of size 4 of char*
char* (*btr)[4]
Now you are trying to assign Array of size 4 of char* to Array of size 4 of char** and they are of different type, so you, obviously, have a error. Still there is another rule(which is dominated): you can't initialize array without curly braces, so array should be initialized with new data not to be a pointer to other array.
And you have absoulutely legal pointer type Pointer to an array of size 4 of char* to which your array address could be assigned

Related

c++ pass array by value or pointer to function syntax

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.

Why is address considered a pointer? [duplicate]

This question already has answers here:
C: differences between char pointer and array [duplicate]
(14 answers)
C++ - Is an array a pointer? [duplicate]
(2 answers)
Closed 7 years ago.
char list[] = "World";
char *ptr = list + 2;
char **p = &ptr;
The question: Why is &ptr of type char**? I understand that p points to a pointer to an array but isn't the address of ptr a char*?
I have looked at Is an array name a pointer?, is it possible that the array is considered a pointer as well in this case?
Is array considered a pointer also?
No, pointers and arrays are distinct types. The confusion arises partly because in many cases pointers can decay to arrays, and in functions, array-like parameters are adjusted to pointers.
Why is &ptr of type char**?
Because ptr is of type char*. Applying the address-of operator to an object of a type gives you a pointer to that type.
I understand that p points to a pointer to an array
No, it points to a pointer, which points to an element of an array.
A pointer to an array is a different type altogether. For example, here a real pointer to an array is made to point to an array:
int a[8];
int (*arr)[8] = &a;
You have to follow things step-wise to easily understand this.
char* ptr is a pointer to char because it is pointing to a char.
What is p pointing at?
It is pointing at a char*. Therefore, it is a pointer to a pointer to a char. That is p is of type char**.
&ptr is a char ** simply because ptr is a char*. list is not a pointer, it's an array. But ptr is declared as char *, so it's a pointer.
ptr is initialised from a pointer list + 2. The expression list + 2 uses the operator +, which performs the array-to-pointer conversion on its operands (if applicable). Therefore, when evaluating list + 2, a temporary pointer to char is created from list using the array-to-pointer conversion. Then another temporary pointer is created by adding 2 to the first one, and this second temporary is then used to initialise ptr.
An array's name "decays" into a pointer to its first element under most circumstances.
In this case, the array consists of 2 bytes. Its name list is a char * pointing to the W.
Consequently, list + 2 points to the r. This pointer is stored into ptr, a char * as well.
A char * is a pointer to char. Consequently, a char ** is a pointer to a pointer to char, and that's exactly what &ptr is.
Array is not a pointer. It is an array. However, array can decay to pointer in certain contexts, of which most notable is passing an array to a function.
A pointer is also the first element of an array, so the address of the first element of the array and the pointer of the array would be the same

Type of different array declarations

What is the type of the array declarations below? Who can say clearly for me what value in case?
int main() {
int* arr[3];
int(*arr)[3];
int*(arr[3]);
}
You can use cdecl to help out:
int *arr[3] gives "declare arr as array 3 of pointer to int".
int (*arr)[3] gives "declare arr as pointer to array 3 of int"
int*(arr[3]) gives "declare arr as array 3 of pointer to int".
Also, of course these are not "real" declarations; there's no terminating semicolons and you can't have three variables called arr in the same scope.
It’s generally a good idea to know the language you use instead of relying on tools to decipher the source code, so I do not recommend using C declaration analyzers.
An easy way to remember the precedence is to remember the signature of main, namely
auto main( int argc, char* argv[] )
-> int
… where you know that argv is an array of pointers (or technically a pointer to the first element of such an array: the declaration decays to char** argv).
That means that given argv you can index it to get a pointer, argv[i], and then dereference the result to get a char, so that the equivalent parenthesized declaration is
char* (argv[])
The declaration
char (*b)[3]
means that by dereferencing b, i.e. *b, you get an array that can be indexed, (*b)[], and so b is a pointer to an array.
It’s not a pointer to the first item of such an array. It’s a pointer to the array itself. Hence adding 1 to b gives you a pointer to a following array of the same size.
Postfix operators such as [] and function call () have higher precedence than unary *, so a declaration like *a[N] will be parsed as *(a[N]), or "N-element array of pointer". To declare a "pointer to N-element array", you need to explicitly group the unary * with the array name, or (*a)[N].
Here's a handy chart.
T a[N] -- N-element array of T
T *a[N] -- N-element array of pointer to T
T (*a)[N] -- pointer to N-element array of T
T f() -- function returning T
T *f() -- function returning pointer to T
T (*f)() -- pointer to function returning T
You can combine the above into pretty complex declarations:
T (*a[N])() -- N-element array of pointers to functions returning T
T (*f())[N] -- Function returning pointer to N-element array of T
T (*(*f())[N])[M] -- Function returning pointer to N-element array of pointer
to M-element array of T
When reading a hairy declaration, start with the leftmost identifier and work your way out, remembering the rules above:
f -- f
f() -- is a function returning ("()" has higher precedence than "*")
*f() -- a pointer to
(*f())[N] -- an N-element array of
*(*f())[N] -- pointers to
(*(*f())[N])[M] -- M-element arrays of
T (*(*f())[N])[M] -- T

what the differences between char** and char*[]

Recently, I need to declare a string array, so I wrote down the following statement:
const char** directories = {"cricket_batting", "cricket_bowling", "croquet", "tennis_forehand", "tennis_serve", "volleyball_smash"};
However, g++ showed me the error:
error: scalar object ‘directories’ requires one element in initializer
So I changed the statement to this:
const char* directories[] = {"cricket_batting", "cricket_bowling", "croquet", "tennis_forehand", "tennis_serve", "volleyball_smash"};
This time, it was right. But I can't exactly know the difference between char** and char[].
= {...};
Initialisation of this form is known as list-initialization.
const char**
This type is a "pointer to pointer to const char".
const char*[]
This type is an "array of pointer to const char".
Simply put, you cannot initialise a pointer with list-initialization. You can initialise an array with list-initialization; it initializes each of the elements in the array with the items in the braced list.
The reason comes down to what exactly you get from a declaration. When you declare a const char**, all you get is a single pointer object. It's a const char**, which is a pointer promising to point at a pointer to const char. Nonetheless, all you actually have is the outer pointer. You can't then initialise this as though it's an array, since you only have one pointer. Where exactly are you going to store the elements of the initialization list? There is no array of pointers in which you can store them.
However, when you declare a const char*[], what you get is an array of pointers. The size of the array is determined by the size of the list because you have omitted it.
The former is a pointer to a pointer to const char while the latter is an array to pointer to const char. The latter is the correct way to initialize an array of strings.
You would need to allocate memory using new to set up char** , for you can't simply initialize pointers with { }.
When you write int a[] we are making an array of integers. Similarly when you write const char* directories[] you are creating an array of char* pointers. Now each char* can point to a char or a string as in your case. This creates individual string constants and assigns the base address of each to the corresponding pointer in the array
char **directories is pointer to a pointer and you can't assign value to a pointer using { .. }

Cannot cast array to pointer

I have the following source:
#include <iostream>
using namespace std;
void main(int j)
{
char arr[10][10];
char** ptr;
ptr = arr;
}
when I compile it using VS2010 I get this error:
error : a value of type "char (*)[10]" cannot be assigned to an entity of type "char **"
I thought arrays in c++ were just pointers. So a char[][] could also be char**. What am I doing wrong?
Arrays aren't pointers.
An array decays to a pointer in most circumstances, but this isn't recursive. So a T[] decays to a T *, but a T[][] doesn't decay to a T**.
I suggest reading the whole of the C FAQ chapter on arrays and pointers; in particular, the section on 2D arrays and pointers-to-pointers.
The existing answers, though correct, don't make it very clear that there is a fundamental reason (apart from the language rules) why you cannot cast char [10][10] to char **. Even if you force the cast by saying something like
char arr[2][2];
char ** ptr = (char **)arr;
it won't actually work.
The reason is that in C and C++ a two-dimensional array is laid out in memory as an array of arrays. That is, in C a two-dimensional array is laid out in memory as a single allocation,
arr -> arr[0][0]
arr[0][1]
arr[1][0]
arr[1][1]
You'll notice that arr doesn't point to a char * but to arr[0][0] which is a char; therefore, while arr can be cast to a char *, it cannot be cast to a char **.
The correct forced cast would be
char arr[2][2];
char * ptr = (char *)arr;
If you don't want to force the cast (always a good idea if possible!) you would say
char arr[2][2];
char * ptr = arr[0];
or, to make the outcome clearer,
char arr[2][2];
char * ptr = &arr[0][0];
And you now have (in effect) a pointer to an array of 4 characters. [Proviso: I can't find anything in the C standard that prohibits an implementation from adding padding between two rows of an array, but I don't believe that any real-world implementations do so, and common coding practice depends on the assumption that there will be no such padding.]
If you really needed to convert arr to a char ** you would have to explicitly create an array of pointers:
char arr[2][2]
char * arr_ptrs[2];
char ** ptr;
arr_ptrs[0] = arr[0];
arr_ptrs[1] = arr[1];
ptr = arr_ptrs;
The C language could in principle do this for you automatically if you tried to cast a two-dimensional array to a pointer-to-pointer but that would violate the programmer's expectation that a cast does not have side-effects such as allocating memory.
In Java, by way of comparison, a two-dimensional array is always an array of pointers to arrays, so that the array
char arr[][] = { {'a', 'b'}, {'c', 'd'} };
is laid out in memory as three separate allocations, in arbitrary order and not necessarily adjacent,
arr -> arr[0]
arr[1]
arr[0] -> arr[0][0]
arr[0][1]
arr[1] -> arr[1][0]
arr[1][1]
You will immediately notice that this requires more memory than the equivalent C array, and is slower to evaluate at runtime. On the other hand, it does allow the rows of an array to have different lengths.
The types char[10][10] and char** and char (*)[10] are all different types. However, the first one cannot convert into the second one, it can convert into the third one.
So try this:
char arr[10][10];
char (*ptr)[10];
ptr = arr; //ok
It will work, because as I said object of type char[10][10] can convert into an object of type char (*)[10]. They're compatible types.
I thought arrays in c++ were just pointers.
No, an array is a set of objects laid out contiguously in memory. In some circumstances, they are convertible to a pointer to the first element.
So a char[][] could also be char**
No. It is convertible to a pointer to the first one-dimensional array (which is the type char (*)[10] mentioned in the error message); but that array is not a pointer, so it is not convertible to a pointer-to-pointer.
The error exactly tells you whats wrong a double dimensional array can be assigned to an pointer to array not an double pointer. So what you need is:
char (*ptr)[10] = arr;
What am I doing wrong?
First things first
Arrays are not pointers!! but they act sometimes like pointers.
The rule is:
An expression with array type (which could be an array name) converts to a pointer anytime an array type is not legal, but a pointer type is.
So if you have a single dimensional array:
char arr[10];
Then arr decays to address of the zeroth element it has the type char *.
Hence:
char *ptr = arr;
But if you have an 2 dimensional array which is essentially an array of arrays.
char arr[10][10];
Then arr decays to the pointer to an array of 10 characters.
So, In order to assign arr to something, you will need that something to match the type, which is pointer to an array of characters.
Hence:
char (*ptr)[10] = arr;
Arrays are NOT just pointers -- arrays are arrays. Arrays are not first-class types, however, so you can't use them in many places. The thing that causes your confusion is that array names CAN be implicitly converted into pointers to the array's first element, which means that you can use an array in many places where you need a pointer and it 'just works'. This, however, is not one of those places.
Arrays are not pointers (I notice a lot of books tend to make you think this, though). They are something completely different. A pointer is a memory address while an array is a contiguous set of some data.
In some cases, an array can decay to a pointer to its first element. You can then use pointer arithmetic to iterate through the contiguous memory. An example of this case would be when passing an array to a function as a parameter.
What you probably want to do here is something like:
char arr[10];
char * i = &arr[0];
Obviously you'll need to use 2D arrays and char** in your case. I'll leave that to you to figure out :)
When you cast ar[10][10] to pointer you will get a array of pointer as said above *ar[10] and not **ar.