Related
int main(){
int a[][3]={1,2,3,4,5,6};
int (*ptr)[3]=a;
printf(" %d",(*ptr)[1]) ;
}
I know that the variable ptr is a pointer of the first 1d array of type int, in other words the variable ptr will store the the address of the first 3 integers, first let's suppose that the base address of a is 1000 so as I think this 2d array will be stored in the memory in this form:
elements: | 1 | 2 | 3 || 4 | 5 | 6 |
addressed of each element: | 1000 | 1004 | 1008 || 1012 | 1016 | 1020 |
---------------------------------||---------------------------------
addressed of each array: 1000 1012
So ptr will store the value 1000 which is the address of the first array. And that means *ptr or (*ptr)[0] will give me the address of the first element, and *ptr+1 or ((*ptr)[1]) will give me the address of the second element and so on.
So as I understand *ptr[1] will give the address of the second element, and not it's value.
But from the output it seem that I am wrong. So I want to know what is the problem in my process.
You are correct until this part:
And that means *ptr or (*ptr)[0] will give me the address of the first element
*ptr will do that. (*ptr)[0] will de-reference the array pointer and then dereference the resulting array, giving you the value of the first item, 1.
Similarly, (*ptr)[1]) will first give you an array and then the second item in that array, 2.
So as I understand *ptr[1] will give the address of the second element, and not it's value.
No, since [] has higher precedence than *, ptr[1] will first give you (the address of) the second array. Then you dereference that and you'll get the the value of the first item in the second array, 4.
The key here is that once you de-reference a pointer to an array, you end up with an array - behaving just like any array would in terms of "array decay" etc.
Best practices:
Do not de-reference array pointers with * if you can avoid it. ptr[0][0] is much less ambiguous. That syntax is the whole point of using array pointers in this case to begin with.
Avoid sloppy initializer lists like int a[][3]={1,2,3,4,5,6};. C allows it but it is bad style and mutes some possibilities of diagnostics. Instead this should have been int a[][3]={ {1,2,3}, {4,5,6} }; which as a bonus is also readable, self-documenting code.
First, it's a good idea to enable compiler warnings. Then you will be informed about missing braces in the initializer. Here is a slightly cleaned up version of your program:
#include <stdio.h>
int main(void)
{
int a[][3] = {{1, 2, 3}, {4, 5, 6}};
int (*ptr)[3] = a;
printf("%d\n", (*ptr)[1]);
return 0;
}
If you run it you will get the output "2". This is because *ptr is the first element of the array a, which itself is an array, and (*ptr)[1] is therefor the second element in this contained array which is 2.
Let's consider the expression used in the call of printf
printf(" %d",(*ptr)[1]) ;
For starters the pointer ptr points to the first element of the type int[3] of the two-dimensional array .
int (*ptr)[3]=a;
That is due to the initializer list
int a[][3]={1,2,3,4,5,6};
the two-dimensional array has two elements of the type int[3].
So dereferencing the pointer *ptr you get an lvalue of the type int[3] that is a one-dimensional array. Then to this array there is applied the subscript operator ( *ptr )[1] that yields the second element of the one-dimensional array.
So the value 2 will be outputted.
And that means *ptr or (*ptr)[0] will give me the address of the first
element
The expression *ptr and ( *ptr )[0] are two entities of different types.The expression*ptryields lvalue of the typeint[3]` , Use din expressions it is in turn can be implicitly converted to a pointer to teh first element of the obtained array.
The expression ( *ptr )[0] yields the first scalar element of the obtained array of the type int.
So as I understand *ptr[1] will give the address of the second
element, and not it's value.
The expression ptr[1] yields the second element of the type int[3] of the two-dimensional array In this expression *ptr[1] the obtained object of the type int[3] is implicitly converted to pointer of the type int * and dereferencing the pointer yields the first element of the type int of the second element of the two-dimensional array.
To make in more clear consider how the subscript operator is evaluated.
For example the expression ptr[0] is equivalent to *( ptr + 0 ) that in turn is equivalent to *ptr.
The expression (*ptr)[1] is equivalent to ptr[0][1].
The expression *ptr[1] is equivalent to *(ptr[1] ) that in turn is equivalent to ptr[1][0].
In general the expression ptr[i][j] can be rewritten in several ways. For example
( *( ptr + i ) )[j]
*( *( ptr + i ) + j )
*( ptr[i] + j )
Is an array's name a pointer in C?
If not, what is the difference between an array's name and a pointer variable?
An array is an array and a pointer is a pointer, but in most cases array names are converted to pointers. A term often used is that they decay to pointers.
Here is an array:
int a[7];
a contains space for seven integers, and you can put a value in one of them with an assignment, like this:
a[3] = 9;
Here is a pointer:
int *p;
p doesn't contain any spaces for integers, but it can point to a space for an integer. We can, for example, set it to point to one of the places in the array a, such as the first one:
p = &a[0];
What can be confusing is that you can also write this:
p = a;
This does not copy the contents of the array a into the pointer p (whatever that would mean). Instead, the array name a is converted to a pointer to its first element. So that assignment does the same as the previous one.
Now you can use p in a similar way to an array:
p[3] = 17;
The reason that this works is that the array dereferencing operator in C, [ ], is defined in terms of pointers. x[y] means: start with the pointer x, step y elements forward after what the pointer points to, and then take whatever is there. Using pointer arithmetic syntax, x[y] can also be written as *(x+y).
For this to work with a normal array, such as our a, the name a in a[3] must first be converted to a pointer (to the first element in a). Then we step 3 elements forward, and take whatever is there. In other words: take the element at position 3 in the array. (Which is the fourth element in the array, since the first one is numbered 0.)
So, in summary, array names in a C program are (in most cases) converted to pointers. One exception is when we use the sizeof operator on an array. If a was converted to a pointer in this context, sizeof a would give the size of a pointer and not of the actual array, which would be rather useless, so in that case a means the array itself.
When an array is used as a value, its name represents the address of the first element.
When an array is not used as a value its name represents the whole array.
int arr[7];
/* arr used as value */
foo(arr);
int x = *(arr + 1); /* same as arr[1] */
/* arr not used as value */
size_t bytes = sizeof arr;
void *q = &arr; /* void pointers are compatible with pointers to any object */
If an expression of array type (such as the array name) appears in a larger expression and it isn't the operand of either the & or sizeof operators, then the type of the array expression is converted from "N-element array of T" to "pointer to T", and the value of the expression is the address of the first element in the array.
In short, the array name is not a pointer, but in most contexts it is treated as though it were a pointer.
Edit
Answering the question in the comment:
If I use sizeof, do i count the size of only the elements of the array? Then the array “head” also takes up space with the information about length and a pointer (and this means that it takes more space, than a normal pointer would)?
When you create an array, the only space that's allocated is the space for the elements themselves; no storage is materialized for a separate pointer or any metadata. Given
char a[10];
what you get in memory is
+---+
a: | | a[0]
+---+
| | a[1]
+---+
| | a[2]
+---+
...
+---+
| | a[9]
+---+
The expression a refers to the entire array, but there's no object a separate from the array elements themselves. Thus, sizeof a gives you the size (in bytes) of the entire array. The expression &a gives you the address of the array, which is the same as the address of the first element. The difference between &a and &a[0] is the type of the result1 - char (*)[10] in the first case and char * in the second.
Where things get weird is when you want to access individual elements - the expression a[i] is defined as the result of *(a + i) - given an address value a, offset i elements (not bytes) from that address and dereference the result.
The problem is that a isn't a pointer or an address - it's the entire array object. Thus, the rule in C that whenever the compiler sees an expression of array type (such as a, which has type char [10]) and that expression isn't the operand of the sizeof or unary & operators, the type of that expression is converted ("decays") to a pointer type (char *), and the value of the expression is the address of the first element of the array. Therefore, the expression a has the same type and value as the expression &a[0] (and by extension, the expression *a has the same type and value as the expression a[0]).
C was derived from an earlier language called B, and in B a was a separate pointer object from the array elements a[0], a[1], etc. Ritchie wanted to keep B's array semantics, but he didn't want to mess with storing the separate pointer object. So he got rid of it. Instead, the compiler will convert array expressions to pointer expressions during translation as necessary.
Remember that I said arrays don't store any metadata about their size. As soon as that array expression "decays" to a pointer, all you have is a pointer to a single element. That element may be the first of a sequence of elements, or it may be a single object. There's no way to know based on the pointer itself.
When you pass an array expression to a function, all the function receives is a pointer to the first element - it has no idea how big the array is (this is why the gets function was such a menace and was eventually removed from the library). For the function to know how many elements the array has, you must either use a sentinel value (such as the 0 terminator in C strings) or you must pass the number of elements as a separate parameter.
Which *may* affect how the address value is interpreted - depends on the machine.
An array declared like this
int a[10];
allocates memory for 10 ints. You can't modify a but you can do pointer arithmetic with a.
A pointer like this allocates memory for just the pointer p:
int *p;
It doesn't allocate any ints. You can modify it:
p = a;
and use array subscripts as you can with a:
p[2] = 5;
a[2] = 5; // same
*(p+2) = 5; // same effect
*(a+2) = 5; // same effect
The array name by itself yields a memory location, so you can treat the array name like a pointer:
int a[7];
a[0] = 1976;
a[1] = 1984;
printf("memory location of a: %p", a);
printf("value at memory location %p is %d", a, *a);
And other nifty stuff you can do to pointer (e.g. adding/substracting an offset), you can also do to an array:
printf("value at memory location %p is %d", a + 1, *(a + 1));
Language-wise, if C didn't expose the array as just some sort of "pointer"(pedantically it's just a memory location. It cannot point to arbitrary location in memory, nor can be controlled by the programmer). We always need to code this:
printf("value at memory location %p is %d", &a[1], a[1]);
I think this example sheds some light on the issue:
#include <stdio.h>
int main()
{
int a[3] = {9, 10, 11};
int **b = &a;
printf("a == &a: %d\n", a == b);
return 0;
}
It compiles fine (with 2 warnings) in gcc 4.9.2, and prints the following:
a == &a: 1
oops :-)
So, the conclusion is no, the array is not a pointer, it is not stored in memory (not even read-only one) as a pointer, even though it looks like it is, since you can obtain its address with the & operator. But - oops - that operator does not work :-)), either way, you've been warned:
p.c: In function ‘main’:
pp.c:6:12: warning: initialization from incompatible pointer type
int **b = &a;
^
p.c:8:28: warning: comparison of distinct pointer types lacks a cast
printf("a == &a: %d\n", a == b);
C++ refuses any such attempts with errors in compile-time.
Edit:
This is what I meant to demonstrate:
#include <stdio.h>
int main()
{
int a[3] = {9, 10, 11};
void *c = a;
void *b = &a;
void *d = &c;
printf("a == &a: %d\n", a == b);
printf("c == &c: %d\n", c == d);
return 0;
}
Even though c and a "point" to the same memory, you can obtain address of the c pointer, but you cannot obtain the address of the a pointer.
The following example provides a concrete difference between an array name and a pointer. Let say that you want to represent a 1D line with some given maximum dimension, you could do it either with an array or a pointer:
typedef struct {
int length;
int line_as_array[1000];
int* line_as_pointer;
} Line;
Now let's look at the behavior of the following code:
void do_something_with_line(Line line) {
line.line_as_pointer[0] = 0;
line.line_as_array[0] = 0;
}
void main() {
Line my_line;
my_line.length = 20;
my_line.line_as_pointer = (int*) calloc(my_line.length, sizeof(int));
my_line.line_as_pointer[0] = 10;
my_line.line_as_array[0] = 10;
do_something_with_line(my_line);
printf("%d %d\n", my_line.line_as_pointer[0], my_line.line_as_array[0]);
};
This code will output:
0 10
That is because in the function call to do_something_with_line the object was copied so:
The pointer line_as_pointer still contains the same address it was pointing to
The array line_as_array was copied to a new address which does not outlive the scope of the function
So while arrays are not given by values when you directly input them to functions, when you encapsulate them in structs they are given by value (i.e. copied) which outlines here a major difference in behavior compared to the implementation using pointers.
The array name behaves like a pointer and points to the first element of the array. Example:
int a[]={1,2,3};
printf("%p\n",a); //result is similar to 0x7fff6fe40bc0
printf("%p\n",&a[0]); //result is similar to 0x7fff6fe40bc0
Both the print statements will give exactly same output for a machine. In my system it gave:
0x7fff6fe40bc0
I came across a code whoes output I'm not able to understand.The code is-
int main()
{
int a[] = {1, 2, 3, 4, 5, 6};
int *ptr = (int*)(&a+1);
printf("%d ", *(ptr-1) );
return 0;
}
The output of above code is coming out 6, but i think that it should be 1. Please explain why it is 6.
In your question "&a" is address of the whole array a[]. If we add 1 to &a, we get “base address of a[] + sizeof(a)”. And this value is typecasted to int *. So ptr points to the memory just after 6 . ptr is typecasted to "int *" and value of *(ptr-1) is printed. Since ptr points memory after 6,so ptr – 1 points to 6.
&a is an address of array a. Adding 1 to it will increment it to one past the array (adding 24-bytes). Cast operator (int*) cast &a+1 to pointer to int type. ptr-1 will decrement ptr by 4 bytes only and therefore it is the address of last element of array a. Dereferencing ptr - 1 will give the last element which is 6.
Yes, because a is an array having a type int[6]. Therefore, &a gives you the type int (*)[6]. It is not same as pointer to int, it is a pointer to int array.
So, &a + 1 increments the pointer by one of the the array size, pointing past the last element of the array.
Then, taking the address in ptr and doing a -1, decreases the address by a sizeof(*ptr) which is sizeof(int), which gives you the address of last element on the array.
Finally, de-referencing that address, you get the value of the last element , 6. Success.
Because (int*)(&a + 1) uses the whole array as the base type and adds 1 whole size of an array to the address , i.e. adding 24 bytes.
And when you do ptr-1 since ptr type is int it will subtract only 4 bytes.
Its very important to remember the type of the pointer while doing pointer arithmetic.
Following is the CODE SNIPPET to add elements of an array in C language!
Main function :
int main ()
{
int a[3]={10,11,12};
printf("%d\n" , arraysum(a,3) );
}
Arraysum function definition :
int arraysum (int *addr , int len )
{
int sum = 0, i ;
for (i=0 ; i<len ; i++)
sum += addr[i];
return sum ;
}
OUTPUT : 33
QUESTIONS : I know that in the main function the base address of the array a is passed to pointer addr , but after that I am unable to understand how following statement is working :
sum+=addr[i];
Q1 : Next , addr was a pointer variable , then how am I using it as an array in arraysum function ?
Q2 : More importantly when I passed base address of array a to the pointer then how come i am able to access all the elements of array a through it ?
Q1 : Next , addr was a pointer variable , then how am i using it as an array in arraysum function ?
Actually, you have this backwards. The subscript operator [] applies to pointers, not to arrays. Huh? What am I on about? Well when you do array[i] where array is an array, the array actually decays to a pointer to its first element. So you are always applying [] to a pointer. In your case, addr is already a pointer to its first element.
Q2 : More importantly when i passed base address of array a to the pointer then how come i am able to access all the elements of array a through it ?
When you do something[i], it is equivalent to *((something) + (i)). This is just basic pointer arithmetic. Take the pointer pointing at the first element, increment the pointer by i, then dereference it.
It is because of this pointer arithmetic that we can access all of the elements of an array through a pointer to one of its elements.
Q1: You can index pointers as if they were arrays (in fact, array indexing really is pointer indexing). So
addr[i]
is the same as *(addr + i)
Q2: because when you pass an array to a function expecting a pointer, the array decays to a pointer to its first element. So addr points to the first element of a. This is a simplified version of the same phenomenon, without a function call:
int a[] = {1, 2, 3}; // size 3 array of int
int * p = a; // OK: a decays to int*. p points to &a[0]
p[0]; // same as a[0]
Note that despite everything, a and p have different types. a is a size 3 array of int. The type contains size information. p is just a pointer to int. It can point to an element of an array, but it can also point to a single int.
Basically int *addr point to the first element in your array. So if you say addr[i] it equals to *(addr + i), which points to the ith element.
When you pass plain array to function, it decays to a pointer. So, we would talk about pointer from now onwards.
If you get a pointer to memory location (ptr) what all things you could do with it:-
de-reference it
*ptr
increment it
++ptr;
etc...
So, this function doesn't know you have an array. You happen to behave in this function as this pointer is pointer into as array. That means you can increment it to get to the next element of an array as array elements are in consecutive memory location. However, you have to ensure that you don't cross the bound. For that you explicitly pass size of array to this function.
Is an array's name a pointer in C?
If not, what is the difference between an array's name and a pointer variable?
An array is an array and a pointer is a pointer, but in most cases array names are converted to pointers. A term often used is that they decay to pointers.
Here is an array:
int a[7];
a contains space for seven integers, and you can put a value in one of them with an assignment, like this:
a[3] = 9;
Here is a pointer:
int *p;
p doesn't contain any spaces for integers, but it can point to a space for an integer. We can, for example, set it to point to one of the places in the array a, such as the first one:
p = &a[0];
What can be confusing is that you can also write this:
p = a;
This does not copy the contents of the array a into the pointer p (whatever that would mean). Instead, the array name a is converted to a pointer to its first element. So that assignment does the same as the previous one.
Now you can use p in a similar way to an array:
p[3] = 17;
The reason that this works is that the array dereferencing operator in C, [ ], is defined in terms of pointers. x[y] means: start with the pointer x, step y elements forward after what the pointer points to, and then take whatever is there. Using pointer arithmetic syntax, x[y] can also be written as *(x+y).
For this to work with a normal array, such as our a, the name a in a[3] must first be converted to a pointer (to the first element in a). Then we step 3 elements forward, and take whatever is there. In other words: take the element at position 3 in the array. (Which is the fourth element in the array, since the first one is numbered 0.)
So, in summary, array names in a C program are (in most cases) converted to pointers. One exception is when we use the sizeof operator on an array. If a was converted to a pointer in this context, sizeof a would give the size of a pointer and not of the actual array, which would be rather useless, so in that case a means the array itself.
When an array is used as a value, its name represents the address of the first element.
When an array is not used as a value its name represents the whole array.
int arr[7];
/* arr used as value */
foo(arr);
int x = *(arr + 1); /* same as arr[1] */
/* arr not used as value */
size_t bytes = sizeof arr;
void *q = &arr; /* void pointers are compatible with pointers to any object */
If an expression of array type (such as the array name) appears in a larger expression and it isn't the operand of either the & or sizeof operators, then the type of the array expression is converted from "N-element array of T" to "pointer to T", and the value of the expression is the address of the first element in the array.
In short, the array name is not a pointer, but in most contexts it is treated as though it were a pointer.
Edit
Answering the question in the comment:
If I use sizeof, do i count the size of only the elements of the array? Then the array “head” also takes up space with the information about length and a pointer (and this means that it takes more space, than a normal pointer would)?
When you create an array, the only space that's allocated is the space for the elements themselves; no storage is materialized for a separate pointer or any metadata. Given
char a[10];
what you get in memory is
+---+
a: | | a[0]
+---+
| | a[1]
+---+
| | a[2]
+---+
...
+---+
| | a[9]
+---+
The expression a refers to the entire array, but there's no object a separate from the array elements themselves. Thus, sizeof a gives you the size (in bytes) of the entire array. The expression &a gives you the address of the array, which is the same as the address of the first element. The difference between &a and &a[0] is the type of the result1 - char (*)[10] in the first case and char * in the second.
Where things get weird is when you want to access individual elements - the expression a[i] is defined as the result of *(a + i) - given an address value a, offset i elements (not bytes) from that address and dereference the result.
The problem is that a isn't a pointer or an address - it's the entire array object. Thus, the rule in C that whenever the compiler sees an expression of array type (such as a, which has type char [10]) and that expression isn't the operand of the sizeof or unary & operators, the type of that expression is converted ("decays") to a pointer type (char *), and the value of the expression is the address of the first element of the array. Therefore, the expression a has the same type and value as the expression &a[0] (and by extension, the expression *a has the same type and value as the expression a[0]).
C was derived from an earlier language called B, and in B a was a separate pointer object from the array elements a[0], a[1], etc. Ritchie wanted to keep B's array semantics, but he didn't want to mess with storing the separate pointer object. So he got rid of it. Instead, the compiler will convert array expressions to pointer expressions during translation as necessary.
Remember that I said arrays don't store any metadata about their size. As soon as that array expression "decays" to a pointer, all you have is a pointer to a single element. That element may be the first of a sequence of elements, or it may be a single object. There's no way to know based on the pointer itself.
When you pass an array expression to a function, all the function receives is a pointer to the first element - it has no idea how big the array is (this is why the gets function was such a menace and was eventually removed from the library). For the function to know how many elements the array has, you must either use a sentinel value (such as the 0 terminator in C strings) or you must pass the number of elements as a separate parameter.
Which *may* affect how the address value is interpreted - depends on the machine.
An array declared like this
int a[10];
allocates memory for 10 ints. You can't modify a but you can do pointer arithmetic with a.
A pointer like this allocates memory for just the pointer p:
int *p;
It doesn't allocate any ints. You can modify it:
p = a;
and use array subscripts as you can with a:
p[2] = 5;
a[2] = 5; // same
*(p+2) = 5; // same effect
*(a+2) = 5; // same effect
The array name by itself yields a memory location, so you can treat the array name like a pointer:
int a[7];
a[0] = 1976;
a[1] = 1984;
printf("memory location of a: %p", a);
printf("value at memory location %p is %d", a, *a);
And other nifty stuff you can do to pointer (e.g. adding/substracting an offset), you can also do to an array:
printf("value at memory location %p is %d", a + 1, *(a + 1));
Language-wise, if C didn't expose the array as just some sort of "pointer"(pedantically it's just a memory location. It cannot point to arbitrary location in memory, nor can be controlled by the programmer). We always need to code this:
printf("value at memory location %p is %d", &a[1], a[1]);
I think this example sheds some light on the issue:
#include <stdio.h>
int main()
{
int a[3] = {9, 10, 11};
int **b = &a;
printf("a == &a: %d\n", a == b);
return 0;
}
It compiles fine (with 2 warnings) in gcc 4.9.2, and prints the following:
a == &a: 1
oops :-)
So, the conclusion is no, the array is not a pointer, it is not stored in memory (not even read-only one) as a pointer, even though it looks like it is, since you can obtain its address with the & operator. But - oops - that operator does not work :-)), either way, you've been warned:
p.c: In function ‘main’:
pp.c:6:12: warning: initialization from incompatible pointer type
int **b = &a;
^
p.c:8:28: warning: comparison of distinct pointer types lacks a cast
printf("a == &a: %d\n", a == b);
C++ refuses any such attempts with errors in compile-time.
Edit:
This is what I meant to demonstrate:
#include <stdio.h>
int main()
{
int a[3] = {9, 10, 11};
void *c = a;
void *b = &a;
void *d = &c;
printf("a == &a: %d\n", a == b);
printf("c == &c: %d\n", c == d);
return 0;
}
Even though c and a "point" to the same memory, you can obtain address of the c pointer, but you cannot obtain the address of the a pointer.
The following example provides a concrete difference between an array name and a pointer. Let say that you want to represent a 1D line with some given maximum dimension, you could do it either with an array or a pointer:
typedef struct {
int length;
int line_as_array[1000];
int* line_as_pointer;
} Line;
Now let's look at the behavior of the following code:
void do_something_with_line(Line line) {
line.line_as_pointer[0] = 0;
line.line_as_array[0] = 0;
}
void main() {
Line my_line;
my_line.length = 20;
my_line.line_as_pointer = (int*) calloc(my_line.length, sizeof(int));
my_line.line_as_pointer[0] = 10;
my_line.line_as_array[0] = 10;
do_something_with_line(my_line);
printf("%d %d\n", my_line.line_as_pointer[0], my_line.line_as_array[0]);
};
This code will output:
0 10
That is because in the function call to do_something_with_line the object was copied so:
The pointer line_as_pointer still contains the same address it was pointing to
The array line_as_array was copied to a new address which does not outlive the scope of the function
So while arrays are not given by values when you directly input them to functions, when you encapsulate them in structs they are given by value (i.e. copied) which outlines here a major difference in behavior compared to the implementation using pointers.
NO. An array name is NOT a pointer. You cannot assign to or modify an array name, but you can for a pointer.
int arr[5];
int *ptr;
/* CAN assign or increment ptr */
ptr = arr;
ptr++;
/* CANNOT assign or increment arr */
arr = ptr;
arr++;
/* These assignments are also illegal */
arr = anotherarray;
arr = 0;
From K&R Book:
There is one difference between an array name and a pointer that must
be kept in mind. A pointer is a variable, but an array name is not a
variable.
sizeof is the other big difference.
sizeof(arr); /* size of the entire array */
sizeof(ptr); /* size of the memory address */
Arrays do behave like or decay into a pointer in some situations (&arr[0]). You can see other answers for more examples of this. To reiterate a few of these cases:
void func(int *arr) { }
void func2(int arr[]) { } /* same as func */
ptr = arr + 1; /* pointer arithmetic */
func(arr); /* passing to function */
Even though you cannot assign or modify the array name, of course can modify the contents of the array
arr[0] = 1;
The array name behaves like a pointer and points to the first element of the array. Example:
int a[]={1,2,3};
printf("%p\n",a); //result is similar to 0x7fff6fe40bc0
printf("%p\n",&a[0]); //result is similar to 0x7fff6fe40bc0
Both the print statements will give exactly same output for a machine. In my system it gave:
0x7fff6fe40bc0