Pointers And Structures

  1. Structure is usually a collection of dissimilar data types; unlike an array which is a collection
    of similar data types. Usually a structure is declared first followed by definition of a structure
    variable as shown below:

    /* declaration of a structure */
    struct book
    {
    char name[20] ;
    int numpages ;
    float price ;
    } ;

    /* definition of a structure variable */
    struct book b ;

  2. A structure variable can be initialized at the same place where it is being defined, as in
    struct book b = { "Basic", 425, 135.00 } ;

  3. Declaration of a structure and definition of a structure variable can be combined into one. When this
    done mentioning the structure name is optional.

    struct
    {
    char name[20] ;
    int numpages ;
    float price ;
    } b = { "Basic", 425, 135.00 } ;

  4. Size of a structure variable is sum of sizes of its individual elements. For example, size of b
    in (c) above is: 20 + 2 + 4 = 26 bytes.

  5. Elements of a structure are stored in adjacent memory locations. For example, the following program would produce the output
    4001, 4021, 4023.


  6. struct book
    {
    char name[20] ;
    int numpages ;
    float price ;
    } ;
    struct book b = { "Basic", 425, 135.00 } ;
    printf ( "%u %u %u", b.name, &b.numpages, &b.price ) ;

  7. It is possible to build an array of structures.
    struct book
    {
    char name[20] ;
    int numpages ;
    float price ;
    } ;
    struct book b[ ] = {
    { "Basic", 425, 135.00 },
    { "Pascal", 500, 155.00 },
    { "VBasic", 625, 335.00 }
    } ;

  8. Nested structures are legal as in:

    struct address
    {
    char city[20] ;
    long int pin ;
    } ;
    struct emp
    {
    char n[20] ;
    int age ;
    struct address a ;
    float s ;
    } ;
    struct emp e = { "Rahul", 23, "Nagpur", 440010, 4000.50 } ;

  9. Contents of one structure variable can be copied either into another structure variable either piece
    meal or at one shot. This is shown below:

    struct book
    {
    char name[20] ;
    int numpages ;
    float price ;
    } ;

    struct book b1 = { "Basic", 425, 135.00 } ;
    struct book b2, b3 ;

    /* piecemeal copying */
    strcpy ( b2.n, b1.n ) ;
    b2.numpages = b1.numpages ;
    b2.price = b1.price ;

    /* copying at one shot */
    b3 = b2 ;

  10. Elements of a structure can be passed to a function.

    main( )
    {
    struct book
    {
    char name[20] ;
    int numpages ;
    float price ;
    } ;

    struct book b1 = { "Basic", 425, 135.00 } ;

    /* mixed call - call be value + call by reference */
    display ( b1.name, b1.numpages, b1.price ) ;

    /* pure call by reference */
    show ( b1.name, &b1.numpages, &b1.price ) ;
    }

    display ( char *n, int nop, float pr )
    {
    printf ( "%s %d %f", n, nop, pr ) ;
    }

    display ( char *n, int *nop, float *pr )
    {
    printf ( "%s %d %f", n, *nop, *pr ) ;
    }

  11. Entire structure can also be passed to a function.

    // declaration must be global.
    // Otherwise diaplay1() and show1() can't use it
    struct book
    {
    char name[20] ;
    int numpages ;
    float price ;
    } ;

    main( )
    {
    struct book b1 = { "Basic", 425, 135.00 } ;
    // call be value
    display1 ( b1 ) ;

    // call by reference
    show1 ( &b1 ) ;
    }

    display1 ( struct book b2 )
    {
    printf ( "%s %d %f", b2.name, b2.numpages, b2.price ) ;
    }

    show1 ( struct book *b2 )
    {
    printf ( "%s %d %f", ( *b2 ).name, ( *b2 ).numpages, ( *b2 ).price ) ;
    printf ( "%s %d %f", b2->name, b2->numpages, b2->price ) ;
    }

  12. Self referential structures contain a pointer to itself within its declaration. These are necessary for building linked lists.

    struct node
    {
    int data ;
    node *link ;
    } ;

What will be the output of the following program

main( )

{

struct s1

{

char *z ;

int i ;

struct s1 *p ;

} ;

static struct s1 a[ ] = {

{ "Nagpur", 1, a + 1 },

{ "Raipur", 2, a + 2 },

{ "Kanpur", 3, a }

} ;

struct s1 *ptr = a ;

printf ( "\n%s %s %s", a[0].z, ptr->z, a[2].p->z ) ;

}

Output
Nagpur Nagpur Nagpur

Explanation:
The zeroth and first elements of struct s1 are a char pointer and an int respectively. The second element is what's new.
It is a pointer to a structure. That is, p stores the starting address of a structure variable of the type struct s1. Next, a[ ], an array of such structures is declared as well as initialised. During initialisation the base address of "Nagpur" is stored in a[0].z, 1 is stored in the element a[0].i, and a + 1 is assigned to a[0].p. On similar lines, the remaining two elements of the array are initialised. a[1].z, a[1].i and a[1].p are assigned "Raipur", 2 and a + 2 in that order, and "Kanpur", 3 and a are stored at a[2].z, a[2].i and a[2].p respectively. What exactly do a, a + 1 and a + 2 signify? a, of course, is the base address of the array a[ ]. Let us assume it to be 4000, as shown in Figure 1. Locations 4000 and 4001 are occupied by the char pointer a[0].z, since a pointer is always two bytes long.

The next two bytes are used to store the integer a[0].i, and then 4004 and 4005 are used by a[0].p. Similarly, the next 6 bytes store the first structure a[1], and the 6 bytes after that contain a[2], the second structure in the array.


Figure 1.

Now, when we say a + 1, we do not arrive at 4001, but at 4006. This is because on incrementing any pointer, it points to the next location of its type. a points to the zeroth structure in the array, i.e. a[0]. Hence, on incrementing a, it will point to the next immediate element of its type, i.e. the first structure a[1] of the array. Likewise, a + 2 signifies the address of the second element a[2] of the array. Thus, a[0].p contains address 4006 (refer figure), a[1].p contains 4012, and a[2].p stores 4000. A struct pointer ptr is now set up, which is assigned a, the base address of the array. In the printf( ), a[0].z denotes the address from where "Nagpur" is stored. Hence "Nagpur" gets printed out. Since ptr contains the address of a[0], ptr->z refers to the contents of element z of the array element a[0]. Thus ptr->z gives the address A0 (refer figure) and this address happens to be the base address of the string "Nagpur". Hence "Nagpur" gets printed out. Let us now analyse the expression a[2].p->z. The left side of the arrow operator always represents the base address of a structure. What structure does a[2].p point to? Looking at the figure we can confirm that a[2].p contains the address 4000, which is the base address of the array a[ ]. Hence the expression a[2].p->z can also be written as a->z. Since a is the base address of the structure a[0], this expression refers to the element z of the zeroth structure. Thus, "Nagpur" gets printed for the third time.

What will be the output of the following program

main( )

{

struct s1

{

char *str ;

int i ;

struct s1 *ptr ;

} ;

static struct s1 a[ ] = {

{ "Nagpur", 1, a + 1 },

{ "Raipur", 2, a + 2 },

{ "Kanpur", 3, a }

} ;

struct s1 *p = a ;

int j ;

for ( j = 0 ; j <<= 2 ; j++ )

{

printf ( "\n%d " , --a[j].i ) ;

printf ( "%s" , ++a[j].str ) ;

}

}

Output
0 agpur
1 aipur
2 anpur

Explanation
The example deals with a structure similar to the one we just encountered. Picking up from the for loop, it is executed for 3 values of j: 0, 1 and 2. The first time through the for loop, j is equal to zero, so the first printf( ) prints --a[0].i. Since the dot operator has a higher priority, first a[0].i is evaluated, which is 1. As -- precedes the value to be printed, 1 is first decremented to 0, and then printed out.

The second printf( ) prints the string at address ++a[0].str. a[0].str gives the starting address of "Nagpur". On incrementing, it points to the next character, `a' of "Nagpur", so starting from `a', the remaining string "agpur" is outputted. A similar procedure is repeated for j = 1, and then once again for j = 2, following which the execution is terminated.

0 comments: