Let us take an example :--
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = NULL;
For the variable arr, will there be any memory allocation ??
Now, what will happen if =>
p = arr;
p = &arr;
p = &arr[0];
Please help me out to understand this.
Let us take an example :--
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = NULL;
For the variable arr, will there be any memory allocation ??
Now, what will happen if =>
p = arr;
p = &arr;
p = &arr[0];
Please help me out to understand this.
This declaration:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
causes 10 * sizeof (int) bytes to be allocated to hold the 10-element array object. (No space for any pointer object is allocated.) The array is initialized as specified.
int *p = NULL;
creates a single pointer object and initializes it to contain a null pointer value.
p = arr;
arr is an expression of array type. In most contexts, its value is implicitly converted to a pointer to its first element. So this assignment causes p to point to the first (0th) element of arr; *p == 1.
p = &arr;
This is invalid. &arr is of type int(*)[10], or pointer to array of 10 ints. p is of type int*. The types are incompatible. Any conforming C compiler must diagnose this error. (The diagnostic may be a non-fatal warning, but don't let that fool you; it's still an error, what the C standard calls a "constraint violation".)
p = &arr[0];
This is identical to p = arr;. arr[0] is the first (0th) element of the array, an int object with the value 1. &arr[0] is the address of that int object, and is of type char*. So this also causes p to point to the initial element of the array arr.
After this assignment, you can use either arr or p as the prefix for an indexing operator. The indexing operator is actually defined to take a pointer, not an array, as its prefix, so arr[0] uses the result of the array-to-pointer conversion, making it identical to p[0].
But arr and p still cannot always be used interchangeably. For example, sizeof arr gives you the size of the array object (10 * sizeof (int)), while sizeof p gives you the size of a pointer (sizeof (int*)).
Suggested reading: Section 6 of the comp.lang.c FAQ.
(To answer the question in your title, the compiler doesn't, or at least isn't required to, allocate memory at run time for the name of an array. It won't allocate 3 bytes of memory at run time because you named your array arr, or 22 bytes because you called it array_with_a_long_name. It might do so for debugging purposes, but then any such allocated space isn't accessible to your program.)
arr[10] creates locations for 10 ints.
p = arr ;
p= &arr[0] ;
are the same thing.
&arr is not something generally useful. It is a int (*)[10] which the compiler should complain about assigning to p.
In fact, if you do a little test and print out the addresses of these three:
printf("X: %lx %lx %lx\n", (long) arr, (long) &arr, (long) &arr[0]) ;
gcc ends up giving you the same thing for all three cases.
% ./a.out
X: 7fff906b5b20 7fff906b5b20 7fff906b5b20
But where you can really see the difference is if you ask for each item +1 :
printf("X: %lx %lx %lx\n", (long) arr, (long) &arr, (long) &arr[0]) ;
printf("X+1: %lx %lx %lx\n", (long) (arr +1), (long) ( &arr +1) , (long) ( &arr[0] +1 )) ;
% ./a.out
X: 7fff73c105b0 7fff73c105b0 7fff73c105b0
X+1: 7fff73c105b4 7fff73c105d8 7fff73c105b4
arr +1 is four bytes larger than arr (the size of an int), as is &arr[0] +1, but &arr +1 is forty bytes larger, the size of the entire array.
&arr is not an int**; it's an int(*)[10], a pointer to an array of 10 ints. For &arr to be an int**, arr would have to be a pointer object; it isn't. At least in this case, C and C++ are equally type conscious in this case, requiring a diagnostic for the error (C calls it a "constraint violation", I'm not sure what C++ calls it). But a diagnostic can be a non-fatal warning. It's a difference in how strict the compilers choose to be, not a language issue.&arr would assign to an int **" -- Still incorrect. There is no int** (unless you take the address of p, the only int* object in the code).p = &arr; is invalid.Storage is not set aside for variable names (arrays or otherwise), except to support debuggers.
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize an 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 this expression will be the address of the first element of the array.
So, taking your three cases:
p = arr;
The expression arr has type "10-element array of int". Since it is not the operand of either the sizeof or unary & operators, it is converted to an expression of type "pointer to int", or int *, and its value is the address of the first element of the array.
p = &arr;
The expression arr has type "10-element array of int". Since arr is the operand of the unary & operator, the conversion above is not performed; instead, the type of the expression &arr is "pointer to 10-element array of arr", or int (*)[10]. The value is the same as the above expression (the address of the array is the same as the address of the first element of the array), but the types of the two expressions are different (int * vs. int (*)[10]), and types matter for things like pointer arithmetic.
p = &arr[0];
Gives the same type and result as p = arr;.
For your array, storage is set aside as follows:
+----+
arr[0]: | |
+----+
arr[1]: | |
+----+
... ...
+----+
arr[9]: | |
+----+
Note that there is no separate storage for a variable named arr that points to the beginning of the array; that pointer value is inferred from the array expression as described above. You can assign to arr[N], but there's no separate arr to assign anything to (part of the reason why array expressions are non-modifiable lvalues).