Pointers And Arrays

An array is a collection of similar elements stored in adjacent memory locations.

int a[] = { 10, 13, -24, -35, 67 } ;

float b[] = { 1.2, 3.44, -5.44, 6.7, 8.9 } ;

long int c[25] ;

If an array is defined and initialized at the same place mentioning its dimension is optional.

If similarity and adjacency considerations are met we can build an array of anything, like say, an array of doubles, an array of structures, an array of pointers etc.

Size of an array is sum of sizes of individual elements of an array.

Base address of an array if address of zeroth element of the array.

Mentioning the name of the array fetches its base address.

int a[] = { 10, 13, -24, -35, 67 } ;

printf ( "%u %u", a, &a[0] ) ; // both would give base address

Array can be passed to a function element by element. Alternatively we can pass the entire array to a function at one shot.

int a[] = { 10, 13, -24, -35, 67 } ;

int i ;

// passing the array element by element

for ( i = 0 ; i <>

display ( a[i] ) ;

// passing entire array

show ( a, sizeof ( a ) / 2 ) ;

To pass an entire array we simply need to pass its base address. Whenever we pass an entire array to the function we also need to pass the size of the array, since the function has no way to find out how many elements are present in the array.

Array elements can be accessed using the subscript notation or the pointer notation.

int a[] = { 10, 13, -24, -35, 67 } ;

int i ;

// access using subscript notation

for ( i = 0 ; i <>

printf ( "%d", a[i] ) ;

// accessing using pointer notation

for ( i = 0 ; i <>

printf ( "%d", * ( a + i ) ) ;

Subscript notation is converted by the compiler into the pointer notation. Hence pointer notation would work faster since using it we would be able to save on the conversion time.

All four following expression are same:

a[i]

* ( a + i )

( * i + a )

i[a]

In the expression a[i]

Out of a and i one must be an integer. The other may either be an array name or a pointer.

An array of pointers is different than a pointer to an array.

int *a[10] ;

int ( *b )[10] ;

a is an array of pointers, whereas, b is pointer to an array. Incrementing a using a++ is illegal. On incrementing b it would start pointing to the next location of its type.

What would be the output of following program

main( )

{

int arr[ ] = { 0, 1, 2, 3, 4 } ;

int *ptr ;

for ( ptr = arr + 4 ; ptr >>= arr ; ptr-- )

printf ( "%d ", arr [ ptr - arr ] ) ;

}

Output
4 3 2 1 0

Explanation
A picture is worth a thousand words. Going by this dictum, the following figure 1 should add clarity to your understanding of the program.


Figure 1.

Now things are getting really complicated, as the printf( ) would justify. Let us begin with the for loop. Firstly ptr is assigned the address 6012, the address of the fourth integer from the base address. Since this address is greater than the base address, the condition is satisfied and the control reaches printf( ) . What does arr [ ptr - arr ] evaluate to? ptr - arr means 6012 - 6004 , which yields 4, and hence arr[4] prints out the fourth element of the array. Then ptr-- reduces ptr to 6010. Since 6010 is greater than the base address 6004, the condition is satisfied and once again the control reaches the printf( ) . This time ptr - arr becomes 6010 - 6004 , i.e. 3. Thus arr[3] prints out 3. This process is repeated till all the integers in the array have been printed out. Possibly an easier way of understanding the expression ptr - arr would be as follows. Suppose ptr contains 6012 and arr contains 6004. We can then view the subtraction as ( arr + 4 - arr ) , since ptr is nothing but arr + 4 . Now I suppose its quite logical to expect the result of the subtraction as 4.

What would be the output of following program

main( )

{

static int a[ ] = { 0, 1, 2, 3, 4 } ;

static int *p[ ] = { a, a + 1, a + 2, a + 3, a + 4 }

int **ptr = p

printf ( "\n%u %d", a, *a )

printf ( "%u %u %d", p, *p, **p )

printf ( "\n%u %u %d", ptr, *ptr, **ptr ) ;

}

Output
6004 0
9016 6004 0
9016 6004 0

Explanation
Look at the initialisation of the p[ ] . During initialisation, the addresses of various elements of the array a[ ] are stored in the array p[ ] . Since p[ ] contains addresses of integers, it has been declared as an array of pointers to integers. Figure 2 shows the content a[ ] and p[ ] . In the variable ptr , the base address of the array p[ ] , i.e. 9016 is stored. Since this address is the address of p[0] , which itself is a pointer, ptr has been declared as pointer to an integer pointer. Let us understand the printf( ) now. The first printf( ) is quite simple. printf ( "\n%u %d", a, *a ) ; It prints out the base address of the array a[ ] and the value at this base address.


Figure 2

Looking at the figure 2, this would turn out to be 6004 and 0. When you execute the program, the address may turn out to be something other than 6004, but the value at the address would be surely 0.

Now look at the second printf( ) .
printf ( "\n%u %u %d", p, *p, **p ) ;

Here p would give the base address of the array p[ ] , i.e. 9016; *p would give the value at this address, i.e. 6004; **p would give the value at the address given by *p , i.e. value at address 6004, which is 0. Now onto the last printf( ) .

printf ( "\n%u %u %d", ptr, *ptr, **ptr ) ;

Here ptr contains the base address of the array p[ ] , i.e. 9016; *ptr would give the value at this address, i.e. 6004; **ptr would give the value at the address given by *ptr , i.e. value at address 6004, which is 0.

What would be the output of following program

main( )

{

static int a[ ] = { 0, 1, 2, 3, 4 } ;

static int *p[ ] = { a, a + 1, a + 2, a + 3, a + 4 } ;

int **ptr = p ;

ptr++ ;

printf ( "\n%d %d %d", ptr - p, *ptr - a, **ptr ) ;

*ptr++ ;

printf ( "\n%d %d %d", ptr - p, *ptr - a, **ptr ) ;

*++ptr ;

printf ( "\n%d %d %d", ptr - p, *ptr - a, **ptr ) ;

++*ptr ;

printf ( "\n%d %d %d", ptr - p, *ptr - a, **ptr ) ;

}

Output
1 1 1
2 2 2
3 3 3
4 4 4

Explanation
Figure 3 would go a long way in helping to understand this program.

Here ptr has been declared as a pointer to an integer pointer and assigned the base address of the array p[ ] , which has been declared as an array of pointers. What happens when ptr++ gets executed? ptr points to the next integer pointer in the array p[ ] . In other words, now ptr contains the address 9018. Now let us analyse the meaning of ptr - p , *ptr - a and **ptr .

ptr - p

Since ptr is containing the address 9018, we can as well say that ptr is containing the address given by p + 1 . Then ptr - p is reduced to ( p + 1 - p ) , which yields 1.

*ptr - a ;

*ptr means value at the address contained in ptr . Since ptr contains 9018, the value at this address would be 6006. Now 6006 can be imagined as ( a + 1 ) . Thus the expression becomes ( a + 1 - a ) , which is nothing but 1.

**ptr

ptr contains 9018, so *ptr yields 6006, and hence **ptr becomes *( 6006 ) , which yields 1.

Thus the output of thefirst ; printf( ) becomes 1 1 1.

Take a deep breath and then begin with the analysis of *ptr++ . Here * and ++ both are unary operators. Unary operators have an associativity of right to left, hence ++ is performed before * . ++ increments ptr such that ptr now contains 9020. Then *( 9020 ) is performed, which gives the value at 9020. But since this value is not assigned to any variable, it just gets ignored. Now with ptr containing 9020, let us once again analyse the expressions ptr - p , *ptr - a and **ptr .


Figure 3.

ptr - p

Since ptr contains 9020, it can be visualised as ( p + 2 ) . Thus ptr - p would become ( p + 2 - p ) , which gives 2.

*ptr - a

*ptr would give value at address 9020, i.e. 6008, which is nothing but the address given by a + 2 . Thus the expression becomes ( a + 2 - a ) , which gives 2.

**ptr

*ptr gives the value at address 9020, i.e. 6008, and *( 6008 ) gives the value at 6008, i.e. 2.

I hope your confidence is building and you are ready to meet head on the expression *++ptr . Here, since ++ precedes ptr , firstly ptr is incremented such that it contains the address 9022, and then the value at this address is obtained. Since the value is not collected in any variable, it gets ignored. Now having cooked enough pointer stew you can easily imagine that the output of the third printf( ) would be 3 3 3.

Finally, let us understand the expression ++*ptr . Here obviously, the priority goes to the * . Thus, this expression increments the value given by *ptr . Since ptr contains 9022, *ptr gives value at 9022, i.e. 6010. This value is incremented to 6012.

So p[3] now contains 6012, whereas value of ptr remains stationary at 9022. Let us now analyse the expressions ptr - p , *ptr - a and **ptr .

ptr - p

ptr contains 9022, therefore ptr can be imagined as ( p + 3 ) . Thus ( ptr - p ) becomes ( p + 3 - p ) , which yields 3.

*ptr - a

*ptr yields 6012 which can be thought of as ( a + 4 ) . Thus the expression is reduced to ( a + 4 - a) , which yields 4.

**ptr

*ptr yields 6012, therefore **ptr would yield the value at *ptr , or the value at 6012, which is >4.

0 comments: