Pankaj Goyal
Pankaj Goyal

Reputation: 1548

Does C compiler allocates memory for variable name used for declaring an array?

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.

Upvotes: 3

Views: 252

Answers (3)

woolstar
woolstar

Reputation: 5083

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.

Upvotes: 1

Keith Thompson
Keith Thompson

Reputation: 263357

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.)

Upvotes: 4

John Bode
John Bode

Reputation: 123508

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).

Upvotes: 1

Related Questions