This post is more of a type of confirmation post rather than a particular question.
I read up some answers on this site and other places to clear up my confusion regarding pointers of type, ex- int(*)[size] which are pointers to an array. From what I've understood, there are some basic differences which I concluded on - 1) pointer arithmetic, 2) dereferencing . I wrote up this code to differentiate between int* and int(*)[size].
int arr1[5] {} ;
int (*ptr1) [5] = &arr1 ;
(*ptr1)[3] = 40 ;
cout << ptr1 << endl ;
cout << ptr1[3] << endl;
cout << ptr1 3 << endl ;
int arr2[5] {} ;
int* ptr2 = arr2 ;
ptr2[3] = 40 ;
cout << ptr2 << endl ;
cout << ptr2[3] <<endl ;
cout << ptr2 3 << endl ;
On observing the output of arithmetic on int(*)[size] its evident that when we add say i to it , it jumps over a block of 4*size*i memory whereas the int* jumps over a 4*i memory block. Also in int* the expression of the form ptr2[i] is equivalent to *(ptr2 i) but in pointers of type int(*)[size] this is not the case ptr1[i] is equivalent to (ptr1 i) and to replicate the action of ptr2[i] we have to do (*ptr1)[i] in this case.
Are there anymore significant differences between the pointers of such type and which pointer amongst them should be preferred and why ? Please correct my analysis if I have gone wrong somewhere .
CodePudding user response:
There are no differences between different kinds of pointers.
If p
has the type T*
, p k
is the address k * sizeof(T)
away from p
.
If p
is the location of an object that is not an array element (as is the case when you acquire it with &
), p[3]
and p 3
are both undefined.
(In this case, p[0]
is the only well-defined indexing, and p 0
and p 1
are the only well-defined arithmetical expressions – but you're not allowed to dereference p 1
.)
Your pointer-to-array code is more similar to this int*
version:
int x = 0;
int* ptr2 = &x ;
ptr2[3] = 40 ;
cout << ptr2 << endl ;
cout << ptr2[3] <<endl ;
cout << ptr2 3 << endl ;
which you can probably see is Just Wrong.
CodePudding user response:
Are there anymore significant differences between the pointers of such type and which pointer amongst them should be preferred and why ?
Yes, the first snippet with ptr1[3]
results in undefined behavior as you're trying to access memory(pointed by ptr1 3
) that is not meant to be accessed by you.
Note that just the expression ptr1 3
is well-defined but if we try to dereference this like *(ptr1 3)
or ptr1[3]
then we will have undefined behavior.
Undefined behavior means anything1 can happen(from C standard's perspective) including but not limited to the program giving your expected output. But never rely on the output of a program that has undefined behavior.
On the other hand, ptr2[3]
is well-defined.
1For more reading(technical definition of) on undefined behavior you can refer to undefined behavior's documentation which mentions that: there are no restrictions on the behavior of the program.