Pointer arithmetic and arrays: what's really legal? - c

Consider the following statements:
int *pFarr, *pVarr;
int farr[3] = {11,22,33};
int varr[3] = {7,8,9};
pFarr = &(farr[0]);
pVarr = varr;
At this stage, both pointers are pointing at the start of each respective array address. For *pFarr, we are presently looking at 11 and for *pVarr, 7.
Equally, if I request the contents of each array through *farr and *varr, i also get 11 and 7.
So far so good.
Now, let's try pFarr++ and pVarr++. Great. We're now looking at 22 and 8, as expected.
But now...
Trying to move up farr++ and varr++ ... and we get "wrong type of argument to increment".
Now, I recognize the difference between an array pointer and a regular pointer, but since their behaviour is similar, why this limitation?
This is further confusing to me when I also consider that in the same program I can call the following function in an ostensibly correct way and in another incorrect way, and I get the same behaviour, though in contrast to what happened in the code posted above!?
working_on_pointers ( pFarr, farr ); // calling with expected parameters
working_on_pointers ( farr, pFarr ); // calling with inverted parameters
.
void working_on_pointers ( int *pExpect, int aExpect[] ) {
printf("%i", *pExpect); // displays the contents of pExpect ok
printf("%i", *aExpect); // displays the contents of aExpect ok
pExpect++; // no warnings or errors
aExpect++; // no warnings or errors
printf("%i", *pExpect); // displays the next element or an overflow element (with no errors)
printf("%i", *aExpect); // displays the next element or an overflow element (with no errors)
}
Could someone help me to understand why array pointers and pointers behave in similar ways in some contexts, but different in others?
So many thanks.
EDIT: Noobs like myself could further benefit from this resource: http://www.panix.com/~elflord/cpp/gotchas/index.shtml

The difference is because for farr++ to have any effect, somewhere the compiler would need to store that farr will evaluate to the address of the second element of the array. But there is no place for that information. The compiler only allocates place for 3 integers.
Now when you declare that a function parameter is an array, the function parameter won't be an array. The function parameter will be a pointer. There are no array parameters in C. So the following two declarations are equivalent
void f(int *a);
void f(int a[]);
It doesn't even matter what number you put between the brackets - since the parameter really will be a pointer, the "size" is just ignored.
This is the same for functions - the following two are equivalent and have a function pointer as parameter:
void f(void (*p)());
void f(void p());
While you can call both a function pointer and a function (so they are used similar), you also won't be able to write to a function, because it's not a pointer - it merely converts to a pointer:
f = NULL; // error!
Much the same way you can't modify an array.

In C, you cannot assign to arrays. So, given:
T data[N];
where T is a type and N is a number, you cannot say:
data = ...;
Given the above, and that data++; is trying to assign to data, you get the error.
There is one simple rule in C about arrays and pointers. It is that, in value contexts, the name of an array is equivalent to a pointer to its first element, and in object contexts, the name of an array is equivalent to an array.
Object context is when you take the size of an array using sizeof, or when you take its address (&data), or at the time of initialization of an array. In all other contexts, you are in value context. This includes passing an array to a function.
So, your function:
void working_on_pointers ( int *pExpect, int aExpect[] ) {
is equivalent to
void working_on_pointers ( int *pExpect, int *aExpect ) {
The function can't tell if it was passed an array or a pointer, since all it sees is a pointer.
There are more details in the answers to the following questions:
type of an array,
sizeof behaving unexpectedly,
Also see this part of C for smarties website, which is very well-written.

Trying to increment farr or varr fails because neither one is a pointer. Each is an array. The name of an array, when evaluated by itself (except as the operand of the sizeof or address-of operator) evaluates to a value (an rvalue) that's of the correct type to be assigned to a pointer. Trying to increment it is a bit like trying to increment 17. You can increment an int that contains the value 17, but incrementing 17 itself won't work. The name of an array is pretty much like that.
As for your second part, it's pretty simple: if you attempt to declare a function parameter of array type, the compiler silently "adjusts" it to a pointer type. As such, in your working_on_pointers, aExpect and pExpect have exactly the same type. Despite the array-style notation, you've defined aExpect as having type 'pointer to int'. Since the two are the same, it's entirely expected that they'll act the same.

Have a look at this answer I posted in relation to differences between pointers and arrays here on SO.
Hope this helps.

okay, i may be wrong. but arrays and pointers can be used alternately.
int * ptr = (int *)malloc(2* sizeof(int));
ptr[0]=1;
ptr[1]=2;
printf ("%d\n", ptr[0]);
printf ("%d\n", ptr[1]);
here i declared a pointer and now i am treating it as array.
moreover:
As a consequence of this definition,
there is no apparent difference in the
behavior of the "array subscripting"
operator [] as it applies to arrays
and pointers. In an expression of the
form a[i], the array reference "a"
decays into a pointer, following the
rule above, and is then subscripted
just as would be a pointer variable in
the expression p[i] (although the
eventual memory accesses will be
different, as explained in question
2.2). In either case, the expression x[i] (where x is an array or a
pointer) is, by definition, identical
to *((x)+(i)).
reference: http://www.lysator.liu.se/c/c-faq/c-2.html

you need to understand the basic concept of arrays.
when you declare an array i.e
int farr[]
you are actually declaring a pointer with this declaration
const int * farr
i.e; a "constant" pointer to integer. so when you do farr++ you are actually trying to add up to a pointer which is constant, hence compilers gives you an error.
if you need to understand, try to declare a pointer with the above declaration and you would not be able to do the arithmetic which are legal on normal pointers.
P.S:
its been quiet a while i have coded in C so i am not sure about exact syntax. but bottom line is the difference between a pointer and a constant pointer.

Related

Why is char*p[10] considered char** p by the compiler? [duplicate]

This question already has answers here:
Should I use char** argv or char* argv[]?
(10 answers)
Closed 8 years ago.
I've been fiddling around to see if there's any way to retain information about an array's length automatically when passed into a function (see my other question here: Why is this array size "workaround" giving me a warning?), but my question is more about a warning that gcc is giving that doesn't make sense to me.
According to this website (EDIT: I misread the website), char *p[10] declares a pointer to a 10-wide array of chars. But when I tried to pass in a pointer to an array into a function, I got this error message from the compiler:
Here is the rest of the program:
I know that when an array is passed into a function, it decays into a pointer (losing information about its length), but it seems that the declaration itself is decaying. What's going on here?
EDIT: When I replace the char *p[10] with char (*p)[10], it doesn't give the warning anymore, and more importantly, it displays the proper array length: 10. I guess my questions are 1) Why do the parentheses change things? and 2) Is this a well-known workaround or am I relying on some behavior of the compiler that isn't guaranteed? (i.e. that array length info can be passed by indirectly passing in a pointer to it?)
In fact char *p[10] is an array, of length 10, of pointers to char. You are looking for char (*p)[10]. That is a pointer to an array, of length 10, of char.
You might find http://cdecl.org/ a useful resource to help you test your understanding of declarations.
Regarding the discussion surrounding dynamic arrays, you are going to have to accept that once you allocate an array dynamically, the system provides no means for you to recover the length of the array. It is your responsibility to remember that information.
The subject of your question has been answered already but I wanted to address the heart of it, which is "can I encode the length of an array in its type?" Which is in fact what a pointer-to-array does. The real question is whether you can actually gain any brevity or safety from this. Consider that in each scope where you have a declaration of your type, the length still needs to be known a-priori. To show you what I mean let's generalize your example slightly by making 10 a compile-time constant N.
#define N 10
size_t arraylength(char (*arrayp)[N]) {
return sizeof(*arrayp);
}
int main(void) {
char array[N];
assert( arraylength(&array) == N ); //always true
}
So far so good. We didn't have to pass the length of array anywhere. But it's easy to see that anywhere the expression sizeof(*arrayp) is used, we also could have written N. And any place we declare a char(*)[ ], the bracketed length must come from somewhere.
So what if N isn't a compile time constant, and array is either a VLA or a pointer-to-array from malloc? We can still write and call arraysize, but it looks like this:
size_t arraylength(size_t N, char (*arrayp)[N]) {
return sizeof(*arrayp);
}
int main(void) {
size_t N = length_from_somewhere();
char array[N];
assert( arraylength(sizeof(array), &array) == N );
}
In defining arraysize N must still be visible before the declaration of arrayp. In either case, we can't avoid having N visible outside of the declaration of arrayp. In fact, we didn't gain anything over writing arraysize(size_t N, char* array) and passing array directly (which is a bit silly given the purpose of this function.) Both times arraylength could have equally been written return N;
Which isn't to say that array pointers are useless as parameters to functions -- in the opposite situation, when you want to enforce a length, they can provide type checking to make sure somefunc(char (*)[10]); receives a pointer to an array that is really (sans shady casting) 10 elements long, which is stronger than what a construct like [static 10] provides.
Also keep in mind that all of the length measurements above depend on the underlying type being char where length == size. For any larger type, taking the length requires the usual arithmetic e.g.
sizeof(*arrayp)/sizeof((*arrayp)[0])
In C, arrays decay to pointers to their first elements on most uses. In particular, what a function receives is always just a pointer to the first element, the size of the array is not passed with it.
Get a good text on C and read up on arrays.
I've been fiddling around to see if there's any way to retain information about an array's length automatically when passed into a function
The problem is so annoying that lots of programmers would love to have an answer. Unfortunately, this is not possible.
It seems that the declaration itself is decaying
Pointer to an array is not the same as a pointer to a pointer; that is why you are getting an error.
There is no decaying going on in your code, because you are not passing an array in your code sample: instead, you are trying to pass a pointer to an array &p. The pointer to an array of characters is not compatible to the expected type of the function, which is char**. Array size from the declaration is ignored.
You need to keep in mind two things:
1. Arrays are not pointers.
2. Array names decays to pointers (in most cases) when passed as arguments to functions.
So, when you declare
int a[10]; // a is an array of 10 ints
int *b; // b is a pointer to int
both of a and b are of different types. Former is of type int [10] while latter is of type int *.
In case of function parameter
void foo1 (int a[10]); // Actually you are not passing entire array
void foo2 (int a[]); // And that's why you can omit the first dimension.
void foo3 (int *a); // and the compiler interprets the above two third
ain all of the above function declarations is of same data type int *.
Now in your case
unsigned long arraySize(char *p[10]);
you can declare it as
unsigned long arraySize(char *p[]);
and hence
unsigned long arraySize(char **p);
All are equivalent.
char *p[10] char *p[] and char **p all are exactly equivalent but when they are declared as parameter of a function otherwise char *p[10] (an array of 10 pointers to char) and char **p (a pointer to pointer to char)are entirely of different type.
Suggested reading: C-FAQ: 6. Arrays and Pointers explains this in detailed.
Array name itself is a constant pointer. for example int arr[10]={0};
arr contains the address of arr[0]. hence arr equals&arr[0] .
when u pass the arraysize(&p) , you are actually passing a double pointer .
The correct format to pass a array pointer would be arraysize(&p[0]) or arraysizeof(p)
Note Array name is constant pointer , you cant change its value .
int arr[10];
arr++;
is invalid.
In your case you cant find a size of an array in function by passing the array name . it would return size of pointer(4 or 8 depends on your processor .
The method is to pass the size along with the array
func(array_name , array_size);

why the actual parameter is altered in the first code?

//reference from Herbert Schildt//
This is the first code
void change(char *);
int main(void)
{
char target[80]="hello";
change(target);
printf("%s",target);//printing aaaaa
return 0;
}
void change(char *tar)
{
int i;
for(i=0;i<strlen(tar);i++)
{
tar[i]='a';
}
}
this is the second code
void change(char *);
int main(void)
{
char target[80]="hello";
change(target);
printf("%s",target);/printing hello
return 0;
}
void change(char *tar)
{
int i;
tar="aaaaa";
}
despite of not passing address of
target
why the string in
target
is getting altered in first code but not in second
why first code is printing
aaaaa
and second code print
hello
The first piece of code changes the contents of the characters pointed to by tar. The second piece changes the local variable tar Itself to point to a different memory location, not the contents of the original memory pointed to. Thus, the original content in main() is preserved in the second case.
Quick answer: In both cases, what's being passed to the change function is a pointer value (not a pointer object). That pointer value is the address of the first element of the target array. In the first example, the change function modifies the array that that pointer points to. In the second example, the change function modifies the pointer. Specifically, it modifies the function's local copy of the pointer, which has no effect on the caller.
//reference from Herbert Schildt//
There's your first problem. Herbert Schildt has written several books on C, but he really doesn't know the language very well. Read some reviews of his books written by actual C experts: The Annotated Annotated C Standard, written by Clive D.W. Feather, and C: The Complete Nonsense, written by Peter "Seebs" Seebach.
I don't know which book your examples came from. His use of int main(void), which is correct, probably indicates that it's one of his later books; in his earlier books he uses void main(void), which is blatantly incorrect (or at least gratuitously non-portable).
Find a better book.
In your first example:
void change(char *tar);
...
char target[80]="hello";
change(target);
the parameter tar is a pointer. That pointer is not changed; the change function changes what the pointer points to. target is an array object, but there's a special-case rule in C that says that an expression of array type is implicitly converted to a pointer to the array's first element in most contexts. (The exceptions are when the array is the operand of a unary & or sizeof operator, or when it's a string literal in an initializer used to initialize an array object; none of those apply here.)
So in the call change(target), the argument passed to the change function is a pointer to (equivalently, the address of) the array element target[0]; the call change(&target[0]) would be exactly equivalent. And via pointer arithmetic, the function can change not just the char object that the pointer points to, but other char objects that are elements of the same array. (The [] indexing operator is defined in terms of pointer arithmetic.)
Incidentally, this loop:
for(i=0;i<strlen(tar);i++)
/* ... */
is horribly inefficient. It recomputes strlen on each iteration of the loop, and each recomputation traverses the entire string.
The change function in the second example is quite different:
void change(char *tar)
{
int i;
tar="aaaaa";
}
The assignment copies a pointer value, not an array value. (There are no array assignment in C; that's why we have functions like strcpy and memcpy.) tar, like in the first example, is a parameter of pointer type. A parameter is a local variable that take its initial value from the corresponding argument passed by the caller. The assignment modifies that local variable (so it points to the array associated with the string literal), but it has no effect on the value passed in by the caller.
Finally, in both examples, the main program does this:
printf("%s",target);
(Incidentally, it should be "%s\n", not just '%s".) The result of evaluating the expression target does not change; it's the base address of the array, and that's fixed as long as the array exists. So why does the output change? Because the %s format specifier, unlike any other printf format specifier, prints not the value of the corresponding argument, but the value of what it points to.
Suggested reading: section 6 of the comp.lang.c FAQ, titled "Arrays and Pointers". It's the best resource I know of for explaining the often confusing relationship between arrays and pointers in C.
char *string = "something between quotes"
when you use double quotes in C and put a string inside it, C automatically creates an array for us and puts the stuff between the double quotes to that new array, and the pointer to that new array is now put in the string variable. in your case "aaaa" will make a new array somewhere in memory(probably in the data section) and then the pointer to this new array is given to tar, expressions are evaluated from right to left, so first "aaaaa" is evaluated and then the result of this is given to tar. so basically always use double quotes "sometinh here" when you initialise an array.
#Filipe Goncalves answer is the correct answer, I couldn't write this in a comment, so had to make a new post.

Clarification about copying an array by referencing a pointer

So I have this array in a header file like this:
// header.h
static const unsigned int array1[]={0x00,0x01,0x02,0x03};
And:
// file.c
main()
{
unsigned int *ptrToArray;
ptrArray = &array1[0];
}
Correct me if I am wrong. I assume: to find the number of bytes of array elements, instead of sizeof(array1) the equivalent will be sizeof(*ptrArray), right?
And to access the elements of the array, instead of array[i], it will now be:
*(ptrArray) for the first element,
*(ptrArray+1) for the 2nd element so on right?
The type of *ptrToArray is int, therefore sizeof(*ptrToArray) is the same as sizeof(int). So it won't tell you anything about the number of elements in array1.
Whilst you can write *(ptrArray+1), etc., you should just write ptrToArray[1]!
A pointer is not an array, and an array is not a pointer. An array can decay into a pointer when convenient, but it is still a complete type.
So, the type of *someIntPointer is int, not an array, even if that pointer happens to point to the first element in an array. sizeof(someArray) works as you would expect because it knows that the type is actually an array.
sizeof won't behave in the same way for your pointer: your example will give you the size of the datatype: unsigned int.
And while you can use pointer arithmetic to reference elements through ptrArray, you can just as well use standard array dereferencing: ptrArray[0], ptrArrray[1], ... and in most cases you're better off doing so.
Sizeof will return the size of the pointer for regular pointer types. If you sizeof a dereferenced pointer type, you will get the size of the element (i.e. sizeof(unsigned int)). You will need to either keep track of the number of elements in the array yourself, or use sizeof on the array declaration.
As for accessing, you could do it that way, but you can just use the bracket notation as you would with a normal array.
Arrays are a special class of pointer. The compiler knows when to treat an array as an array and when to treat it as a pointer: that's how it knows how big an array is, but you can still pass it to functions that expect an array (when you do this, you get a pointer to the first element). The same does not work in reverse however: The compiler will never treat a pointer declared as a pointer as an array.
By the way, [] just simplifies to pointer arithmetic. You can add a pointer to an int, but you can also add an int to a pointer. You can thus (but probably shouldn't) do weird things like 1[ptrArray]

How does an array pointer store its size? [duplicate]

This question already has answers here:
Why isn't the size of an array parameter the same as within main?
(13 answers)
Closed 7 years ago.
#include "stdio.h"
#define COUNT(a) (sizeof(a) / sizeof(*(a)))
void test(int b[]) {
printf("2, count:%d\n", COUNT(b));
}
int main(void) {
int a[] = { 1,2,3 };
printf("1, count:%d\n", COUNT(a));
test(a);
return 0;
}
The result is obvious:
1, count:3
2, count:1
My questions:
Where is the length(count/size) info stored when "a" is declared?
Why is the length(count/size) info lost when "a" is passed to the test() function?
There's no such thing as "array pointer" in C language.
The size is not stored anywhere. a is not a pointer, a is an object of type int[3], which is a fact well known to the compiler at compile time. So, when you ask the compiler to calculate sizeof(a) / sizeof(*a) at compile time the compiler knows that the answer is 3.
When you pass your a to the function you are intentionally asking the compiler to convert array type to pointer type (since you declared the function parameter as a pointer). For pointers your sizeof expression produces a completely different result.
Where is the length(count/size) info stored when "a" is declared?
It's not stored anywhere. The sizeof operator (used in the COUNT() macro) returns the size of the entire array when it's given a true array as the operand (as it is in the first printf())
Why is the length(count/size) info lost when "a" is passed to the test() function?
Unfortunately, in C, array parameters to functions are a fiction. Arrays don't get passed to functions; the parameter is treated as a pointer, and the array argument passed in the function call gets 'decayed' into a simple pointer. The sizeof operator returns the size of the pointer, which has no correlation to the size of the array that was used as an argument.
As a side note, in C++ you can have a function parameter be a reference to an array, and in that case the full array type is made available to the function (i.e., the argument doesn't decay into a pointer and sizeof will return the size of the full array). However, in that case the argument must match the array type exactly (including the number of elements), which makes the technique mostly useful only with templates.
For example, the following C++ program will do what you expect:
#include "stdio.h"
#define COUNT(a) (sizeof(a) / sizeof(*(a)))
template <int T>
void test(int (&b)[T]) {
printf("2, count:%d\n", COUNT(b));
}
int main(int argc, char *argv[]) {
int a[] = { 1,2,3 };
printf("1, count:%d\n", COUNT(a));
test(a);
return 0;
}
Nowhere.
Because it wasn't stored in the first place.
When you refer to the array in main(), the actual array declaration definition is visible, so sizeof(a) gives the size of the array in bytes.
When you refer to the array in the function, the parameter is effectively 'void test(int *b), and the size of the pointer divided by the size of the thing it points at happens to be 1 on a 32-bit platform, whereas it would be 2 on a 64-bit platform with LP64 architecture (or, indeed, on an LLP64 platform like Windows-64) because pointers are 8 bytes and int is 4 bytes.
There isn't a universal way to determine the size of an array passed into a function; you have to pass it explicitly and manually.
From the comment:
I still have two questions:
What do you mean by "..the actual declaration is visible.."? [T]he compiler (or OS) could get the length info through sizeof(a) function?
Why the pointer &(a[0]) doesn't contain the length info as the pointer "a"?
I think you learned Java before you learned C, or some other more modern language. Ultimately, it comes down to "because that is the way C is defined". The OS is not involved; this is a purely compiler issue.
sizeof() is an operator, not a function. Unless you are dealing with a VLA (variable length array), it is evaluated at compile time and is a constant value.
Inside main(), the array definition (I misspoke when I said 'declaration') is there, and when the sizeof() operator is applied to the name of an actual array - as opposed to an array parameter to a function - then the size returned is the size of the array in bytes.
Because this is C and not Algol, Pascal, Java, C#, ...
C does not store the size of the array - period. That is a fact of life. And, when an array is passed to a function, the size information is not passed to the function; the array 'decays' to a pointer to the zeroth element of the array - and only that pointer is passed.
1. Where is the length(count/size) info stored when "a" is declared?
It isn't stored. The compiler knows what a is and therefore knows it's size. So the compiler can replace sizeof() with the actual size.
2. Why is the length(count/size) info lost when "a" is passed to the test() function?
In this case, b is declared as a pointer (even though it may point to a). Given a pointer, the compiler does not know the size of the data pointed to.
Array pointer does not store the size. However, the[] type is not actually a pointer. It's a different type. When you say int a[] = {1,2,3}; you define array of 3 elements, and since it is defined so, sizeof(a) gives you the size of the whole array.
When however you declare parameter as int a[], it's pretty much the same as int *a, and sizeof(a) would be the size of the pointer (which coincidentally may be the same as the size of int, but not always).
In C, there's no way to store the size in pointer type, so if you need the size, you'd have to pass it as additional argument or use struct.
Where is the length(count/size) info stored when "a" is declared?
Nowhere. The question doesn't make sense BTW.
Why is the length(count/size) info lost when "a" is passed to the test() function?
Array decays into pointer(to the first element) when passed to a function. So the answer is 'nowhere' and similar to the previous question this one again doesn't make any sense.

What do parentheses in a C variable declaration mean?

Can someone explain what this means?
int (*data[2])[2];
What are the parentheses for?
In C brackets [] have a higher precedence than the asterisk *
Good explanation from Wikipedia:
To declare a variable as being a
pointer to an array, we must make use
of parentheses. This is because in C
brackets ([]) have higher precedence
than the asterisk (*). So if we wish to declare a pointer to an array, we need to supply parentheses to override this:
double (*elephant)[20];
This declares that elephant is a
pointer, and the type it points at is
an array of 20 double values.
To declare a pointer to an array of
pointers, simply combine the
notations.
int *(*crocodile)[15];
Source.
And your actual case:
int (*data[2])[5];
data is an array of 2 elements. Each element contains a pointer to an array of 5 ints.
So you you could have in code using your 'data' type:
int (*data[2])[5];
int x1[5];
data[0] = &x1;
data[1] = &x1;
data[2] = &x1;//<--- out of bounds, crash data has no 3rd element
int y1[10];
data[0] = &y1;//<--- compiling error, each element of data must point to an int[5] not an int[10]
There is a very cool program called "cdecl" that you can download for Linux/Unix and probably for Windows as well. You paste in a C (or C++ if you use c++decl) variable declaration and it spells it out in simple words.
If you know how to read expressions in C, then you're one step away from reading complicated declarations.
What does
char *p;
really mean? It means that *p is a char. What does
int (*data[2])[5];
mean? It means that (*data[x])[y] is an int (provided 0 <= x < 2 and 0 <= y < 5). Now, just think about what the implications of that are. data has to be... an array of 2... pointers... to arrays of 5... integers.
Don't you think that's quite elegant? All you're doing is stating the type of an expression. Once you grasp that, declarations will never intimidate you again!
The "quick rule" is to start with the variable name, scan to the right until you hit a ), go back to the variable name and scan to the left until you hit a (. Then "step out" of the pair of parentheses, and repeat the process.
Let's apply it to something ridiculous:
void **(*(*weird)[6])(char, int);
weird is a pointer to an array of 6 pointers to functions each accepting a char and an int as argument, and each returning a pointer to a pointer to void.
Now that you know what it is and how it's done... don't do it. Use typedefs to break your declarations into more manageable chunks. E.g.
typedef void **(*sillyFunction)(char, int);
sillyFunction (*weird)[6];
data[2] - an array of two integers
*data[2] - a pointer to an array of two integers
(*data[2]) - "
(*data[2])[2] - an array of 2 pointers to arrays of two integers.
If you have an array:
int myArray[5];
int * myArrayPtr = myArray;
Would be perfectly reasonable. myArray without the brackets is a pointer to an int. When you add the brackets its like you deference the pointer myArray. You could write...
myArrayPtr[1] = 3;
Which is perfectly reasonable. Using parenthesis just makes things harder to read and understand IMO. And they show that people don't understand pointers, arrays, and pointer arithmetic, which is how the compiler or linker goes from one to the other. It seems with parenthesis you do get bounds checking though.

Resources