CHAPTER 9

Pointers

Pointers are one of the most sophisticated features of the C language. A pointer is just another data type available in C. Understanding pointers needs the understanding of the meaning of an address. Below is given a brief discussion, the study of which helps in understanding the meaning of addresses and pointers.

We have been using variables declaration statements with almost all the functions developed hitherto. It is time to look closely to see what happens when a declaration statement is used. For example, consider the statement

int temp = 10;

The above statement:

  1. Reserves a memory location (of 2 bytes size).
  2. Names the memory location with the name temp.
  3. Stores an integer value 10 in the location.

At the machine level every byte of memory will have a numeric address. Obviously, the memory location reserved during a declaration will have a numeric address. Since every memory location will have an address, this reserved memory location will also have an address. Let this address be 2080. It may be noted that the address values will be unsigned integers.

The size of the memory location reserved depends upon the data type that is expected to be stored in it. For example, char data type uses 1 byte, int data type uses 2 bytes, float data type uses 4 bytes and so on. Thus in our discussion a memory location means one or more continuous bytes. When a memory location having more than one byte is dealt with, the address of the first byte is taken as the address of the location.

The mutual relationship between the various attributes of a variable name mentioned above is shown diagrammatically in the following figure.

images

Knowing address values: the & operator As mentioned in the previous paragraph, every memory location will have an address. The & operator is used to obtain the address of any required memory location. Therefore this operator is also known as the address operator. The value of &temp, in the example given above, is 2080. Thus the address of the memory location with the name temp is 2080. In other words, the name of the memory location with an address 2080 is temp.

It may be noted that we have been using the & operator all along, with scanf (). Thus, during an input operation using scanf ( ) the required memory location is accessed using its address.

Pointers: the * operator In its simplest form “a pointer is defined as something which indicates or points towards something else.”

images

Let x and y are two variables and x has the address value of y stored in it. Obviously, the variable x is looking-at or pointing towards y and hence is known as a pointer.

As a variable like x could have address values of different memory locations stored in it at different points of time, they are also known as pointer variables.

In C, a variable is declared as a pointer by using the * (asterisk) operator. This operator * is known as the indirection operator or the dereferencing operator. Like all other variables, pointers are also declared in the beginning. For example, the variable x mentioned above is declared as a pointer using a declaration statement as shown below

int *x;

When declaration statement like the one given above is used, the following action takes place.

  1. A memory location is reserved.
  2. It will be of pointer type pointing no-where.
  3. The memory location is named as x.
  4. This memory location will have an address.

    images

Thus the more formal way of defining a pointer is that “a variable (like x) that holds the address of another variable (like y), using which one can access the contents of the other variable y”. The other variable is generally called “the target variable” of the pointer. Thus y is the target variable of the pointer variable x. This definition of a pointer can be diagrammatically shown as follows.

images

It is time to understand the need of a data type qualifying a pointer. It is known that the contents of pointers are always address values that are (unsigned) integers. Then why is that pointers are type declared ?: as in int *x; during the declaration of variables. This is because, every pointer will have a target variable which can have any type of value stored in it. It is the data type of this target variable of the pointer which is used during a pointer declaration. Thus in our example int refers to the data type of the possible target variable of the pointer x.

A pointer variable, unless otherwise not initialized, will be always looking at some or the other variable. Whenever a pointer variable is not initialized it will be pointing nowhere (shown with a “?” in the diagrams). It is recommended that a pointer should be initialized. If the user is not sure that where should the pointer be looking at initially, it is customary to make it to look at or point towards the 0th (zeroth) memory location. This is done by assigning the NULL to the pointer. A pointer that is initialized with a NULL and is, therefore, pointing to the 0th location is known as a NULL pointer.

Normally variables within a function access memory locations of the variables within the same function. However, using pointers memory locations of variables in some other function can be accessed. Thus pointers help variables to access more than what they normally could. Pointers have many number of other uses. Some of them are:

  • 1) they are used in called functions to return two or more values to the calling function
  • 2) they are used to access as well as to manipulate the data items of arrays, strings and structures
  • 3) they are used in dynamic memory management.

9.1 UNDERSTANDING PRELIMS OF POINTERS

In this example, a number of declaration statements and assignment statements that extract addresses of certain variables has been discussed. Different memory locations have been accessed both in the classical way (i.e. by using names of the memory locations) and the pointer way (i.e. by using addresses of the memory locations). The output of the example is also given for verification. A detailed discussion regarding what the various statements in the program are doing has been given at the end.

The Program

/* Understanding the prelims of pointers */

#include<stdio.h>
#include<conio.h>
main()
{


   int a = 10;                          /* Line 1 */
   float b = 5.4;                       /* Line 2 */
            /* p is a pointer pointing to an int type data */
   int *p;
                                /* Line 3 */
            /* q is a pointer pointing to a float type data */
   float *q;                            /* Line 4 */
   clrscr();
            /* Assigning address of a to p */
   p = &a;                       /* Line 5 */
            /* Assigning address of b to q */
   q = &b;                       /* Line 6 */
   printf (“The address of a is : %u
”,&a) ;  /* Line 7 */
   printf (“The address of b is : %u
”,&b) ;  /* Line 8 */
   printf (“
The address of a as stored in p = %u
”,p) ; /* Line 9 */
   printf (“The address of b as stored in q = %u

”,q) ; /* Line 10 */
   printf (“The value in a = %d
”,a) ;       /* Line 11 */
   printf (“The value at address in p = %d
”,*p) ;   /* Line 12 */

   printf (“
The value in b = %.2f
”,b) ;       /* Line 13 */
   printf (“The value at address in q = %.2f”,*q) ;   /* Line 14 */
}
            _______ _ OUTPUT_________   
        The address of a is : 65524
        The address of b is : 65520

        The address of a as stored in p = 65524
        The address of b as stored in q = 65520

        The value in a = 10
        The value at address in p = 10

        The value in b = 5.40
        The value at address in q = 5.40

Explanation of the behavior of every statement during the program execution is given below.

When line 1 is executed a memory location named a is allocated. The data type of its contents will be integer. An initial value of 10 is stored in it.

images

When line 2 is executed a memory location named b is allocated. The data type of its contents will be float. An initial value of 5.4 is stored in it.

images

When line 3 is executed a memory location named p is allocated. p being a pointer variable, this memory location can store only unsigned integers that are addresses. As this is uninitialized it could be pointing anywhere. However, the target data type has to be int.

images

When line 4 is executed a memory location named q is allocated. q being a pointer variable, this memory location can store only unsigned integers that are addresses. As this is also uninitialized it could be pointing anywhere. However, the target data type has to be float.

images

When line 5 is executed the address of the integer variable a is stored in p. Therefore, here, p is said to be pointing towards a, i.e. the memory location with the address 65524.

images

When line 6 is executed address of the float type variable b is stored in q. Therefore, here, q is said to be pointing towards b, i.e. the memory location with the address 65520. Actions carried out at line number 5 and 6 are in-line with the anticipated actions at lines 3 and 4.

images

When line 7 is executed the address of a is extracted using the address operator (&) and printed out. This address is 65524. When line 8 is executed the address of b is extracted using the address operator (&) and printed out. This address is 65520.

When line 9 is executed the contents of p i.e. 65524, which has to be the address of a, is printed out. On verification with the output of the line 7 it is found correct. When line 10 is executed the contents of q i.e. 65520, which has to be the address of b, is printed out. On verification with the output of the line 8 it is found correct.

When line 11 is executed the value of a is accessed by name, as usual, and printed out. When line 12 is executed the value of a is accessed via p, i.e. the pointerp and printed out. On comparison with the output of line 11 it is found correct.

When line 13 is executed the value of b is accessed by name, as usual, and printed out. When line 14 is executed the value of b is accessed via q, i.e. the pointer q and printed out. On comparison with the output of line 13 it is found correct.

A careful observation of the lines 7 to 10 reveals the fact that we have used the format specifier %u. It may be noted that %u is used to handle unsigned integer values. This is because memory addresses will be always unsigned integers.

Further, observe the different format specifiers used in lines 11, 12, 13 and 14. In lines 11 and 12, %d is used. This is because the variable a is of type int and the target data type of the pointer p is int. In lines 13 and 14, %f is used. This is because the variable b is of type float and the target data type of the pointer q is float.

9.2 UNDERSTANDING POINTER EXPRESSIONS, POINTER-TO-POINTER AND NULL POINTER

It is possible to manipulate the contents of pointers. In other words, pointers can be used in certain types of expressions. The only permitted operators for such pointer manipulations are + (plus), - (minus), ++ (increment), -- (decrement), = (assignment) and the relational operators. Expressions that involve pointers and additions or subtractions of integers to them and comparison of contents of pointers are called pointer expressions. For the purpose of illustration certain statements that involve pointer expressions have been considered in this example. The use of the NULL pointer is also shown in this example. The meaning of ‘pointer to pointer’ is also demonstrated. Below is given an illustrative example.

The Program

/* Pointer Expressions */

#include<stdio.h>
#include<conio.h>
main()
{

   int a = 10, *p, **r, x;                  /* Line 1 */
   float b = 5.4, *q = NULL, y;                 /* Line 2 */
   clrscr();
   printf (“The contents of the pointer q = %u 
”,q) ; /* Line 3 */
   /* Assigning address of a to the pointer p */
   p = &a;                       /* Line 4 */
   /* Assigning address of b to the pointer q */
   q = &b;                       /* Line 5 */
   printf (“The contents of the pointer p = %u 
”,p) ; /* Line 6 */
   printf (“The contents of the pointer q = %u 
”,q) ; /* Line 7 */
   p = p + 3;                                 /* Line 8 */
   q ++;                                  /* Line 9 */
   printf (“
The contents of the pointer p=%u 
”,p) ; /* Line 10 */
   printf (“The contents of the pointer q = %u 
”,q) ; /* Line 11 */

   p -- ;                           /* Line 12 */
   q = q - 3 ;                          /* Line 13 */
   printf (“
The contents of the pointer p=%u 
“,p) ;   /* Line 14 */
   printf (“The contents of the pointer q = %u 
”,q) ;   /* Line 15 */

   r = “p;                       /* Line 16 */
   printf (“
The contents of the pointer p=%u 
”,p) ; /* Line 17 */
   printf (“The contents of the pointer r = %u 
”,r) ; /* Line 18 */

   if (p == q)                         /* Line 19 */
   printf(“
p and q are pointing to the same memory location”); else
   printf(“p and q are pointing to different memory locations”);

   p = &a;                       /* Line 20 */
   x = *p;                          /* Line 21 */
   printf (“
The contents of the pointer p=%u 
”,p) ; /* Line 22 */
   printf(“x=%d
”,x);                /* Line 23 */
   r = &p;                       /* Line 24 */
   printf(“x=%d”,**r);                /* Line 25 */
}

Explanation for each of the executable statements used in the above program is given below.

When line 1 is executed, an integer variable a with an integer value of 10 is created, a pointer p with a target data type of int and pointing nowhere is created, a ‘pointer to pointer’ with a target data type of integer and pointing nowhere is created and an uninitialized integer variable x is also created. When line 2 is executed, a float type variable b with an initial float value of 5.4 is created, a null pointer q with a target data type of float and pointing towards the 0th (zeroth) memory location is created and an uninitialized float type variable y is created. When line 3 is executed, the value printed out will be the address of the location pointed to by q which is 0 (zero). This is found to be the anticipated result. When line 4 is executed, the address of the variable a is extracted and assigned to the pointer P. When line 5 is executed, the address of the variable b is extracted and assigned to the pointer q.

When line 6 is executed, the contents of the pointerp, i.e. the address of the variable a (65524) is printed out. When line 7 is executed, the contents of the pointer q, i.e. the address of the variable b (65516) is printed out. When line 8 is executed, the contents of p(which is an address) is increased by (3x size of the location) 6 and is assigned to p. Thus the contents of p now has to be (65524 + 6) 65530. When line 9 is executed, the contents of q is incremented by 1-memory location size, i.e. 4 bytes. Thus the new contents of q must be 65520. When line 10 is executed, the recently stored contents of the pointer p, i.e. 65530 is printed out. This is found to be correct.

When line 11 is executed, the recently stored contents of the pointer q, i.e. 65520 will be printed out. This is found to be correct. When line 12 is executed, the contents of the pointer variable p will be decreased by 1-memory location size, i.e. 2 bytes. Thus the new contents of p must be now 65528. When line 13 is executed, the contents of the pointer variable q will be decreased by 3-memory location size, i.e. 12 bytes. Thus the new contents of q must be now 65508. When line 14 is executed, the recently stored contents of the pointer p, i.e. 65528 is printed out. This is found to be correct. When line 15 is executed, the recently stored contents of the pointer q, i.e. 65508 is printed out. This is found to be correct.

When line 16 is executed, the address of the pointer p is stored in the “pointer to pointer” r. When line 17 is executed, the contents of pointer p is printed out (65528). This is found to be correct. When line 18 is executed, the contents of “pointer to pointer” r is printed out. This has to be the address of the pointer p. Comparison for equality of two pointers is being made in line 19. Addresses of p and q being different, the printed out result is correct. When line 20 is executed, the address of the variable a is extracted and assigned to the pointer variable p.

When line 21 is executed, the contents of the target location pointed by p, i.e. the variable a is assigned to the variable x, i.e. x value becomes 10. When line 22 is executed, the contents of the pointer p, i.e. the address of a is printed out. This is 65524 and is found to be correct. When line 23 is executed, the value of x is printed. This is found to be correct. When line 24 is executed, the address of the pointer p, i.e. 65522 is assigned to the “pointer-to-pointer” r. When line 25 is executed, the value of the target location (i.e. a) of the “pointer-to-pointer” r is printed out. This is found to be correct.

9.3 FINDING SUM OF ALL ELEMENTS OF ARRAY USING POINTERS

The Method

First all the ‘n’ elements of the array, say a, is read-in. The sum of all the elements of the array is obtained by repeatedly adding every element of the array to the sum using a statement of the form sum = sum + *p; where p is a pointer variable. This pointer variable p should be looking at or pointing-to the successive memory locations of the array, one after the other, starting from the first one to the last one. The pointer p is made to look- at the successive memory locations by adding a 1 to its contents, i.e. by incrementing its contents. Here a for loop structure has been used for adding the contents of the memory locations of the array as well as to point towards successive memory locations. The sum obtained is output finally.

C-Tips

Variable p is declared as a pointer in the declaration statement. Address of the first element of the array may be assigned to p by using a statement of the form p = &a [0] ; or a statement of the form p = a;. Using the statement of the former type is obvious. However, the latter type statement is also permitted because as soon as an array a is declared, the C compiler assigns the first address of the allocated memory area to its name, i.e. to a, here.

Pointer p itself has been used as the loop control variable. Obviously its initial value has to be the address of the first location, i.e. the contents of the array name a or address of a[0], the upper limit has to be the last address of the allocated memory area, i.e. (a + n), and the next address is obtained by incrementing the value of p.

The beginning address of an array or the address of an array can be obtained either by using the array name directly or by using the address-of-operator (&) along with the name of the first location, i.e. &a[0].

With many number of examples involving arrays, we have seen that the arrays are transmitted between different functions by using only the array names, i.e. without the use of any additional effort by the user. Since array names hold the first address of their memory area, when array names are used as arguments of functions, their beginning address will be handed over to the called function. This automatic transfer of array addresses which is equivalent to the classical call-by-reference technique is generally referred to as call by implication.

Further, it may be noted that the size of every memory location and hence the total number of bytes allocated for an array depends on the data type of the elements in the array. Thus, if an array of char data type with 10 elements is declared, then the size of every memory location will be 1 byte and the total number of bytes allocated to the array will be 10 bytes. Similarly, if an array of float data type with 10 elements is declared then the size of every memory location will be 4 bytes and the total number of bytes allocated to the array will be 40.

... beyond

images

When a declaration statement like int a[10]; is declared, 10 continuous memory locations will be allocated to store all the 10 integer elements of the array a. The size of each memory location depends upon the data type of the elements to be stored in these locations. Note that in an array all the elements will be of same data type. Here, as the data type of the array is int, each location will be 2 bytes long. Thus the memory area reserved for the array a will be 20 bytes long, as shown in the adjoining figure.

Let the address of the first memory location, i.e. a[0] be 65524. Then the address of the second memory location a[1] will be 65526, the address of the third memory location a[2] will be 65528 and so on. It is important to note that the contents of an array name, like a,without any subscript will be the first address of the memory area reserved for all its elements. Thus in the above example, the value of a will be 65524, same as that of & a[0].

Flowchart

images

The Program

/* Program to find the sum of all the elements of an array using pointers */

#include<stdio.h>
#include<conio.h>
main()
{
    int i, n, sum=0, a [10] ;  /* Declaring variables */
     int *p ;   /* Declaring a pointer variable */
     clrscr();
     printf (“Read the value of n : ”) ;
     scanf(“%d”, &n);
     printf(“%d
”,n);
     printf(“
The address of a = %u
”,&a[0] ) ;  /* Line # */
     printf (“The value of a = %u

”,a) ;           /* Line # */
     printf(“Read the elements of the array 
” ) ;
     for(i=0; i<n ;i++)
     {
     scanf(“%d”,&a[i]);        /* Reading array elements */
  }

     printf(“
Elements are 
”);
     for(i=0; i<n ;i++)
     printf(“%d
”,a[i]);     /* Printing array elements */

     for(p=a; p<a+n ; ++p)
     sum += *p ;                /* Finding sum */

     printf(“
Sum = %d”,sum);
}

Note: Lines with comments /* Line # */ have been included in order to demonstrate the fact that the address stored in the name a will be same as that of the element a[0].

               __________ OUTPUT__________  
           Read the value of n : 4
           The address of a = 65458
           The value of a = 65458
          Read the elements of the array
           23 12 -12 4
           Elements are
           23
           12
           -12
           4
           Sum = 27

9.4 FUNCTION TO SWAP CONTENTS OF TWO VARIABLES USING POINTERS

Unusually a program that does not work was discussed in Section 8.15. The intention of the discussion there was to make the reader understand why the function swap( ) failed?, whereas it worked when it was developed as a (main) program in Section 2.2. At this stage the reader is advised to browse those examples once again and try to find out the reasons.

The Method

For this example to work, we must see that the concerned variables in the swap () function directly access and work on the relevant memory locations in the main ( ) function. This is achieved by passing on the address of the concerned variables from the main( ) to the corresponding variables in the swap( ). Thus the concerned variables in the swap( ) function should be holding address values, and hence pointing towards the appropriate memory locations in the main( ).

As soon as the called function is recognized, the address values of a and b are transmitted and made as the contents of the pointers p and q. As a result, a sort of coupling takes place between the called function and the calling function. Thus swapping (or any other activity) done with the pointers inside the called function swap( ) actually takes place in the memory locations of the calling function and hence this program works. Notice that the temp is a local variable in the called function and the actual swapping is managed with the variables a, b {in main ( )} and temp in swap ( ). As this swap ( ) function does not return any value its type has been declared as void.

…beyond

When developed as a main( ) function, the swapping activity was a success because the function was manipulating the contents of the memory locations of its local variables a and b directly. However, when developed as a user-defined function (as in Section 8.15), the swapping was a failure because memory locations of variables a and b in the main( ) and the memory locations of the variables a and b in the user-defined function swap ( ) were different. This is because a and b in main() are local to main() and a and b in swap( ) are local to swap (). Memory locations for the local variables of a function will be allocated inside that function itself and are directly accessible only within that function. As a result when the contents of a and b inside the swap( ) were exchanged only memory locations of a and b pertaining to swap( ) got manipulated. In other words, the memory locations of a and b in main() remained unaltered. Hence the failure.

The above reason for failure can be circumvented by providing an ability to the variables inside the swap ( ) function {called function} to access the corresponding variables inside the main ( ) {calling function} and work on those variables directly. The required accessing ability to the variables inside a called function can be granted by providing the address of the memory locations of the variables in a calling function {main( )} to the corresponding variables in the called function {swap( )}.

In the present example, inside the swap( ) function, corresponding values of the local variables a and b of main( ) are x and y. As these variables x and y of swap( ) should be able to access the memory locations of the variables a and b of main( ) they should hold the addresses of a and b, respectively. Obviously, variables x and y have to hold address values of a and b and hence should be pointer variables. Thus, the method used in solving this example is to pass “the address of the variables” from the calling function to the called function and “store them in pointer variables.” This enables the called function to work directly on the memory locations of the calling function. This technique of invoking or calling a function by passing address values, storing them in “pointer variables” and hence providing the ability to these variables to access corresponding variables in the calling function is known as call by address or call by reference. The entire mechanism that depicts the address flow and direct accessing through pointers is schematically shown in the next page.

A study of the schematic diagram given in the next page gives an insight to the mechanism involved in the call by address (i.e. call by reference) method of passing the parameters. When the function swap(&a, &b) inside the main( ) is executed the control goes to the swap( ) function, recognizing it by name. Along with the control, the addresses of a and b also get transmitted to the swap( ) function and become the values of the pointers x and y respectively. It is because address values are to be passed on, the actual arguments are &a and &b, rather than a and b. As address values arrive at the formal arguments of the called function, these formal arguments must be pointers. This is why the formal arguments of swap( ) have been taken as pointers x and y, i.e. as *x and *y. As the contents of the target memory locations of both these pointers are of integer type, the qualifying type of both the pointers *x and *y have been taken as of type int.

images

images

The Program

/* Function to swap the contents of two variables - Using Pointers */

#include<stdio.h>
#include<conio.h>

main()
{
    void swap (int *x, int *y) ;    /* Function prototype */
    int a,b;                /* Local variables */
    clrscr();

    printf (“Enter the values of a & b
” ) ;
    scanf(“%d %d”,&a,&b);

    /* printing the values of a& b before swapping */
    printf(“
 Before swapping (in the calling function). 
a = %d & b
         = %d
”,a,b);


    swap(&a,&b);          /* Calling swap() function */

    /* printing the values of a & b after swapping */
    printf (“
 After swapping ( in the calling function) . 
a = %d & b
         = %d
”,a,b);

}


/* The swap() function */

void swap (int *x, int *y)
{
   int temp;                /* Declaring the local variable */
   /* interchanging the contents of variables a & b */

   temp=*x;/* Contents of the target location of x is put in temp */ *x=*y;
                  /* Contents of the target location
                          y is made as the contents
                  of the target location of x */
*y=temp;       /* Contents of temp is put into the
                                 target location of y */


  /* printing the values of a & b within the function */

  printf (“
 The values of a = %d & b = %d within the called
          function
”,*x,*y);
    
  return;   /* Control going back without any return values! */
}

9.5 SOLVING QUADRATIC EQUATION—USING FUNCTIONS AND POINTERS

The procedure involved in solving a given quadratic equation has been already discussed, in detail, in Sections 3.6 and 5.1. The reader is advised to browse through those sections once again for better understanding.

The Method

The procedure discussed in Sections 3.6 and 5.1 is used here once again. Here, three functions quad_re ( ), quad_rd ( ) and quad_comp ( ) have been developed. The function quad_re( ) has been developed to compute the real and equal roots. The function quad_rd( ) has been developed to compute the real and distinct roots. The function quad_comp( ) has been developed to compute the real and imaginary parts of the complex roots. All the functions have been developed assuming that the co-efficients a and b of the equation, are available. Obviously, a and b have been taken as the formal arguments of all the functions developed here. Computations of real and distinct roots and complex roots require the value of the discriminant disc. Therefore, disc has also been taken as one of the formal arguments while developing quad_rd( ) and quad_comp( ) functions. The two roots computed inside the functions are returned back to the main( ), by using two float type pointers p1 and p2. Thus all the functions have the pointer type variables p1 and p2 as their formal arguments. (Here, one has to carefully notice that why the last two formal arguments have been taken as float *p1 and float *p2). Thus the function headers and the function prototypes of the functions developed here are

void quad_re(float a, float b, float *p1, float *p2)

void quad_rd(float a, float b, float disc, float *p1, float *p2)

void quad-comp(float a, float b, float disc, float *p1, float *p2)

A main ( ) function is developed in which after inputting the co-efficients a, b and c the discriminant disc is computed. Depending upon whether this disc is equal to 0 (zero), is +ve or -ve, one of the functions quad_re ( ), quad_rd ( ) and quad_comp( ) is invoked or called. After getting the required computed values for the roots, the roots are printed out. Flowcharts for all the functions as well as the main( ) function are given in this page as well as the next page.

C-Tips

As functions cannot readily return more than one value to their calling functions, pointers have been used. p1 and p2 are the two pointers used. These pointers are expected to look at or point towards the memory locations of root1 and root2 in main( ). This is accomplished by storing the addresses of the memory locations pertaining to root1 and root2 in the pointer variables, using the statements like p1= p1 = &root1; and p2 = p2 = & root2; in the main( ). Thus the target variable of the pointer p1 is root1 and of the pointer p2 is root2. As these target variables root1 and root2 are expected to store float type values in them, the qualifying type declaration portion of the pointers p1 and p2 have been taken as float. Thus the two pointers have been declared as: float *p1; and float *p2;.

Flowchart

images

When any of the functions to compute roots developed here is invoked or called, the values of a, b and disc are passed on to the called function by-value and the addresses of root1 and root2 are made available via the pointers p1 and p2, respectively. Thus, it may be observed that both the techniques, viz. call-by- value and call-by-reference are being used simultaneously in this example. This is legal and permitted. A careful observation reveals the fact that the computed roots will be directly available in the main( ) function. In other words, no values are returned to the main( ) by any of the user defined functions. Hence, all the functions quad_re( ), quad_rd( ) and quad_comp( ) have been declared as of type void.

images

The Program

/* To find the roots of a given quadratic equation using pointers */

#include<conio.h>         /* Including header files */
#include<stdio.h>
#include<math.h>


main()
{
   float a,b,c,disc, root1, root2;      /* Declaring variables */
   float *p1, *p2 ;             /* Declaring pointers p1 and p2 */


   /* Function prototypes*/
   void quad_re (float a, float b, float *p1, float *p2) ;
   void qua d_rd (float a, float b, float disc, float *p1, float *p2) ;
   void quad_comp (float a, float b, float disc, float *p1, float *p2) ;

   clrscr();                    /* Clearing the Screen */

   p1 = &root1;           /* Initializing pointers */
   p2 = &root2;

   printf(“

Enter co-efficients of the quadratic equation

”);
   scanf (“%f%f%f”, &a, &b, &c) ;
   printf(“
Co-efficients are a = %f	 b = %f	 c = %f

”, a,b,c);

   disc=b*b-4*a*c;          /* Calculating discriminant */

   if ( disc == 0)
           /* If discriminant is zero roots are real and equal */
      {
        quad_ re (a,b, p1, p2);         /* Function call */

    printf(“
Root1 = %f	 Root2 = %f
”,root1,root2);
      }
   else
     {
    if ( disc < 0)
          /* If discriminant is less than zero roots are complex */
      {
     quad_comp(a, b, disc, p1, p2) ;    /* Function call */
     printf(“
Root1 = %f + i %f	Root2 = %f -i %f
”, root1, root2, root1, root2);
      }
    else
       /* If discriminant is greater than zero roots are real and distinct */
     {
       quad_rd(a,b, disc, p1, p2) ;         /* Function call */

       printf(“
Root1 = %f	 Root2 = %f
”,root1,root2);
     }
  }
}
/* Function to find the real and equal roots of equation */
void quad_re(float a,float b, float *p1, float *p2)
{
   printf(“Roots are real and equal
”);
   *p1 = -b/(2.0*a) ;
   *p2 = *p1;
   return;
}

/* Function to find the real and distinct roots of equation */
void quad_rd(float a,float b, float disc, float *p1, float *p2)
{
   printf(“Roots are real and distinct
”);
   *p1 = (-b+sqrt(disc))/(2.0*a);
   *p2 = (-b-sqrt(disc))/(2.0*a);
   return;
}
/* Function to find the complex roots of equation */
void quad_comp(float a,float b, float disc, float *p1, float *p2)
{
   printf(“Roots are complex
”);
   *p1 = -b/(2.0*a) ;
   *p2 = sqrt(-disc)/(2.0*a);
   return;
}

EXERCISES

  1. Write a C program with three array variables each of int, float and char data types, each having 5 data elements that prints out the addresses of each memory location in which the different elements of the declared arrays are stored.
  2. Write a C program having two variables of different data types and to print the values of these variables without using pointers, using pointers and using pointer- to- pointers.
  3. Draw a flowchart to develop a function that finds the highest and the second highest among a given set of float type of data elements and returns them to a calling function {say, main( )}. Code the same using C.
  4. Draw a flowchart to develop a function that counts the number of positive elements, the number of negative elements, computes the average of all the elements of a given array and returns the same to a calling function. Code the same using C.

    [Note: Consider zero (0) element as positive.]

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.176.194