stu nicholls dot com | menu - Professional dropdown #3

Untitled Document

Pointers

Pointer variables are the variables capable of holding the addresses. Before using a pointer variable we must declare the variable as a pointer variable as we declare any other variable. But we must use an indirection operator while declaring a pointer variable.


Syntax :
Type specifier * name of the variable;


Example:

int *ptr;
The above declaration specifies to the compiler that ptr is pointer variable capable of holding the address of an integer variable.

How do we store the address of a variable in a pointer variable?
We can use the ampersand ( & ) sign to specify the address of a variable i.e. by prefixing the ampersand sign (&) with the variable of which we want to store the address.


Syntax:
Pointer variable = & name of the variable of which we want to store the Address;


Example:
ptr = &i;
The above statement stores the address of the variable i in the pointer variable ptr.


Example:
# include <stdio.h>
#include<conio.h>
void main ( )
int i, *j;
i = 5;
j = &i;
printf ("Value stored in i = %d\n", i);
printf ("Address of i stored in j = %u\n", j);
printf ("Value of i obtained using the pointer variable j = %d\n", *j);
getch ( );
}


OutPut:



Note:
(1) The address of i is 8778 and the format specification character of %u i.e. unsigned is selected because format specification character %d will display values only up to 32768.
(2) The value of i is obtained indirectly with the help of the pointer variable j by prefixing the indirection operator (*) with the pointer variable j i.e. *j.

The indirection operator * means value at address.

You can see the address of any variable in memory location by prefixing the ampersand sign (&) to the variable. The following program shows it.

#include<stdio.h>
void main ( )
{
int i=3, *j;
j= &i;
printf ("Address of i is %u\n",j);
printf("Value of i is %d\n",*j);
printf ("Address of j is %u\n",&j);
}


Output:

In the above program you can get the address of the variable i by displaying the contents of pointer variable j and you can even see the address of the pointer variable j by prefixing the ampersand sign with the pointer variable j as shown in the example.

Consider the following examples:
int *a;
char *c;
float *j;
All are pointer variables that is, variables capable of holding addresses. Addresses are always whole numbers. So, when we declare float *j, it does not mean that j is going to contain a floating point value. What it means is j is going to contain the address of a floating point value. Similarly char *c means that c is going to contain the address of a character value.


# include <stdio.h>
#include<conio.h>
void main ( )
{
int i,*ptr1;
float j,*ptr2;
char c,*ptr3;
i=5;
j=54.53;
c='A';
ptr1=&i;
ptr2=&j;
ptr3=&c;
printf("Address of i %u\n",ptr1);
printf("value of i is %d\n",*ptr1);
printf("Address of j %u\n",ptr2);
printf("value of j is %f\n",*ptr2);
printf("Address of c %u\n",ptr3);
printf("Value of c is %c\n",*ptr3);
getch() ;
}

Output:


Now although i occupies 2 bytes in memory, the statement ptr1 = &i; stores only the address of the first byte i.e. 9308 in ptr1.
As we can see from the output memory locations addressed as 9308 and 9309 is allocated to the integer variable i.
Similarly ptr2 = &j; stores only the address of first byte i.e., 9300 out of 4 bytes allocated to j. As we can see from the output, memory locations addressed as 9300, 9301,9302 and 9304 is allocated to the float variable j; similarly the memory location 9295 is allocated to the character variable c.
This address of the first byte is often known as the base address. Although ptr1 and ptr2 are containing only the base address, *ptr1 and *ptr2 will allow the access to all the bytes occupied by the integer variable
i and float variable j respectively. That is why, while defining the pointers, we are defining it by the type of variable’s value it can hold.


Arithmetic on Pointers:
Pointer arithmetic is different than the normal arithmetic. This is because in pointer arithmetic when you increment the pointer or decrement the pointer the quantity by which the pointer increments or decrements depends on the type of the pointer on which the operation is performed.
Increment/Decrement operation:
When you increment or decrement an integer pointer it increments or decrements by two because each of the integer variables are assigned with two bytes. Similarly when you increment or decrement a float pointer it increments or decrements by four because each of the float variables are assigned with four bytes and when you increment or decrement an character pointer it increments or decrements by only one because each of the character variables are assigned with one byte.

Following examples explain this operation:

Example1:
# include<stdio.h>
#include
void main ( )
{
char c, *cc;
c = 'A';
cc = &c;
printf ("Address of c % u\n", cc);
printf ("Value of c is %c\n", *cc);
cc = cc+5;
printf ("Contents of cc %u after incrementing \n", cc);
getch ( );
}


Output:


In the above example address of the variable c is 8745 and when we add 5 to the contents of pointer variable cc it is incremented to 8750.

Example2:
# include <stdio.h>
#include <conio.h>
void main ()
{
int i, *ii;
i = 5;
ii = &i;
printf ("Address of i is %u\n", ii);
printf ("Value of i is %d\n", *ii);
ii = ii+5;
printf ("Content of ii is %u\n", ii);
getch ();
}


Output:


In the above example address of the variable i is 8728 and when we add 5 to the contents of pointer variable ii it is incremented to 8738 because the integer variable is allocated two bytes. Thus 2 ? 5 = 10.

# include <stdio.h>
#include <conio.h>
void main ()
{
float f, *ff;
f = 55.54;
ff = &f;
printf ("Address of f is %u\n", ff);
printf ("Value of f is %f\n", *ff);
ff = ff+5;
printf ("Content of ff is %u\n", ff);
ff = ff-2;
printf ("Content of ff is %u\n", ff);
getch ();
}


Output:


In the above example address of the variable f is 9280 and when we add 5 to the contents of pointer variable ff it is incremented to 9300 because the float variable is allocated four bytes. Thus 4 ? 5 = 20. Similarly when the pointer is decremented by two it's contents are reduced by 8 numbers which is shown in the above example i.e. 9292.

As discussed above in the examples addition of a number to a pointer or subtraction of a number from a pointer is also possible like ff =ff+5; or ff =ff-2;
Note:
Following operations should not be performed on pointer variables.
(1) Addition of pointers.
(2) Multiplying a pointer with a number or another pointer variable.
(3) Dividing a pointer with a number or another pointer variable.

Passing Arguments to a function:
Arguments can generally be passed to functions in one of the two ways.
(1) Sending the values of arguments or call by value.
(2) Sending addresses of arguments or call by reference.


  1. Sending the values of arguments or call by value: Whenever a function is called with parameters passed to it and if the values of the parameters (variables) are passed to the called function, such function calls are called as call by value. By this what we mean is on calling a function we are passing the values of variables to it.

    Example:
    #include <stdio.h>
    #include <conio.h>
    void main ( )
    {
    float radius;
    void area();
    printf("Enter the radius\n");
    scanf("%f", &radius);
    area (radius);
    }
    void area (r)
    float r;
    {
    float ar;
    ar = 3.14 *r * r;
    printf("area of the circle is %f\n",ar);
    }


    Output


    In the above example the value of the radius is copied on to the variable r in the function area();
    In this the value of the actual arguments in the calling function are copied onto the formal arguments of the called function.
    This means that even if we make changes to the values of the formal variables in the called function the value of the actual arguments in the calling function will not change.
    If suppose the value of the variable radius is 5.0 when it was passed to the function area(), but assume if we change the value of the variable r to 10.0 in the function area(), this change will not reflect in the value of the variable radius in the function main() and it is 5.0 only.


    1. Sending addresses of arguments or Call by Reference:
      Whenever a function is called with parameter passed to it and if the addresses of the variables are passed to the called function such a function calls are called as call by reference. By this what we mean is on calling a function we are passing the address of the variable to it.
      In this the address of the actual arguments in the calling function are copied into formal arguments of the called function.
      This means that using the formal variables in the called function we can make changes in the actual arguments of the calling function.

      Example:
      # include <stdio.h>
      # include <conio.h>
      void main ( )
      {
      float radius;
      void area();
      printf("Enter the radius\n");
      scanf("%f", &radius);
      area (&radius);
      }
      void area (r)
      float *r;
      {
      float ar;
      ar = 3.14 *(*r) * (* r);
      printf("area of the circle is %f\n",ar);
      }


      Output:


      In the above example the address of the radius ( &radius- This ampersand sign(&) prefixing the variable radius means that the address of the variable radius) is copied on to the variable r in the function area(); In the function area(), to catch this address the variable r should be a pointer variable so it is depicted with float *r; to mean that r is the pointer variable.
      In this the address of the actual arguments in the calling function are copied onto the formal arguments of the called function. This means that if we make changes to the values of the formal variables in the called function the value of the actual arguments in the calling function will change.
      If suppose the value of the variable radius is 5.0 when it was passed to the function area() but assume if we change the value of the variable pointed by r to 10.0 in the function area(), this change will reflect in the value of the variable radius in the function main() because the pointer variable r is pointing to the variable radius. Following example shows this.


      Example:
      # include <stdio.h>
      # include <conio.h>
      void main ( )
      {
      float radius;
      void area();
      radius=5.0;
      printf("Value of radius before the call of function area is %f\n",radius);
      area (&radius);
      printf("Value of radius after the return from function area is %f\n",radius);
      }
      void area (r)
      float *r;
      {
      float ar;
      ar = 3.14 *(*r) * (* r);
      printf("Area printed in the function area \n");
      printf("Area of the circle is %f\n",ar);
      *r=10.0;
      ar = 3.14 *(*r) * (* r);
      printf("Area of the circle is %f\n",ar);
      }


      Output:


      Note:
      In the above example value of radius when it was passed to the function area() was 5.0. But once the area was calculated with this value the value of the radius was changed with the help of the pointer variable r to 10.0 and again the area was calculated. This new value is reflected in the value of actual argument radius.

      Program to interchange the value of two variables:

      (1) Call by value method:
      # include<stdio.h>
      # include <conio.h>
      void main ( )
      {
      int a, b;
      void swap();
      printf ("Enter the value for a and b\n");
      scanf ("%d %d", &a, &b);
      printf("Value of a and b before calling the function swap \n");
      printf ("a = %d b= %d\n", a, b);
      swap (a, b);
      printf("Value of a and b aftre returning from the function swap \n");
      printf ("a = %d, b = %d\n", a, b);
      getch ( );
      }
      void swap (x, y)
      int x, y;
      {
      int temp;
      temp = x;
      x = y;
      y = temp;
      printf("Value of x and y displayed in tthe function swap \n");
      printf ("x = %d, y = %d\n", x, y);
      }


      Output:



      (2) Call by reference:

      # include<stdio.h>
      # include <conio.h>
      void main ( )
      {
      int a, b;
      void swap ();
      printf ("Enter the values for a and b\n");
      scanf ("%d%d",&a,&b);
      printf ("Values of a and b before invoking the function swap\n");
      printf("a= %d b= %d\n",a,b);
      swap (&a,&b);
      printf ("Values of a and b after the return from swap\n");
      printf("a= %d b= %d\n",a,b);
      getch ( );v }
      void swap (x, y)
      int *x, *y;
      {
      int temp; temp = *x;
      *x = *y;
      *y = temp;v printf("Value of x and y in the function swap\n"); printf ("x = %d y = %d\n", *x, *y);
      }


      Output:


      In this, the address of a and b are copied on to x and y respectively. So whatever changes are made at the locations pointed by x and y it will affect the values of a and b.


      /*Program to calculate the area and perimeter of the circle using call by reference method */
      # include<stdio.h>
      # include <conio.h>
      void main ( )
      {
      int r;
      float area, peri;
      void area_peri();
      printf ("Enter the value of radius \n");
      scanf ("%d", &r);
      area_peri(&r, &area, &peri);
      printf ("area is = %f perimeter is = % f\n", area, peri);
      getch ( );
      }
      void area_peri (x, y, z)
      int *x;
      float *y, *z;
      {
      *y = 3.14 *(*x) * (*x);
      *z = 2 * 3.14 * (*x);
      }


      Output


      Pointers and Arrays:
      When we define one-dimensional array, it is been allocated the consecutive locations in memory. For example if we have declared an array int ar[5]; then the compiler allocates 10 bytes as each location means two bytes as the data type is integer. Following example explains this concept of contiguous allocation.

      #include<stdio.h>
      #include <conio.h>
      void main ()
      {
      int ar[5],*ptr, i;
      ptr = &ar[0];
      printf("Enter five elements for array\n");
      for (i = 0; i<5; i++)
      { scanf ("%d", &ar[i]);
      } for (i=0; i<5; i++)
      {
      //two methods of getting the address of each element
      printf ("Address of array element %u\n", &ar[i]);
      printf ("Contents of ptr %u\n", ptr);
      printf ("Value at address pointed by ptr is %d\n",*ptr);
      ptr++;
      }
      getch ();
      }


      Output:


      As you can observe from the output that starting from memory location 9170 to 9179 ten bytes are allocated for the integer array named as ar with size as five elements. The allocation is continuos memory location.


      Consider the following example:
      #include<stdio.h>
      #include <conio.h>
      void main ()
      {
      int ar[5], i;
      void disp();
      printf("Enter five elements for array\n");
      for (i=0; i<5; i++)
      {
      scanf ("%d",&ar[i]);
      }
      disp (&ar[0]);
      getch ();
      }
      void disp (ptr)
      int *ptr;
      {
      int i;
      printf("Contents of array printed in the function disp\n");
      for (i=0; i<5; i++)
      {
      printf ("%d\n", *ptr);
      ptr++;
      }
      }


      Output:

      In the above example, we are assigning the address of 0th element of array ar to pointer variable ptr. Later we are incrementing the pointer variable ptr to point to the next element of array ar. Thus the for loop will continue till the last element of array ar is accessed using pointers. Thus by assigning ptr=&ar[0] we have collected the base address of ar in the pointer variable ptr i.e. in the main() function disp() is called by passing the address of the starting element of array ar[ ] and in the function disp() the address is received by the pointer variable ptr.

      Note:
      ptr = &ar and ptr=&ar [0] are equivalent.
      Accessing array element by pointer is always faster than accessing them by subscript.


      /* Program to display the contents of an array from last to first using pointers*/
      # include<stdio.h>
      #include <conio.h>
      void main ()
      {
      int ar[5], *ptr, i;
      printf ("Enter five elements \n");
      for (i=0; i<5; i++)
      {
      scanf ("%d", &ar[i]);
      }
      ptr=&ar[4];
      printf ("Entered elements displayed in reverse order \n");
      for (i=0; i<5; i++)
      {
      printf ("%d\n", *ptr);
      ptr--;
      }
      getch ();
      }

      Output:


      In the above example, we are assigning the address of the last element of array ar to the pointer variable ptr and in the for loop, we are accessing the last element of array ar to the first element of ar by decrementing the pointer.
      Passing an entire array to function:
      # include<stdio.h>
      # include <conio.h>
      void main ()
      {
      int ar[5] = {1,2,3,4,5}, m=5;
      void disp();
      disp (&ar[0],m);
      }
      void disp(ptr, n)
      int *ptr, n;
      {
      int i;
      for (i=0; i<n;i++)
      {
      printf ("Address of ar[%d]= %u\n",i,(ptr+i));
      printf (" ar[%d]= %d\n",i, *(ptr + i));
      }
      }


      Output: :


    2. /* Program to send the address of one element at a time to the function and get the value printed in the function.*/

      # include<stdio.h>
      # include <conio.h>
      void main ()
      {
      int i, *j;
      void disp ();
      int ar[5]= {1,2,3,4,5};
      for (i=0; i<5; i++)
      {
      j= &ar[i];
      disp(j);
      }
      getch ();
      }
      void disp (ptr)
      int *ptr;
      {
      printf ("%d\n", *ptr);
      }


      In the above example, during the first iteration of for loop in main() we are passing the address of the 0th element of the array ar[ ] to the function disp() and using the pointer the 0th element of array ar[ ] is displayed. So in the function disp(), ptr is the pointer variable which will have the address of the 0th element of array ar[ ]. During the successive iterations of for loop, addresses of each and every element of array ar[ ] is passed to the function disp() and the element is displayed. Thus, by putting for loop in the main, we are passing the address of 1 element at a time.

      Let us consider a program to find the length of a string using pointers and functions.

      # include <stdio.h>
      # include <conio.h>
      void main ()
      {
      char strn[100], *p;
      void length();
      printf ("Enter the string :\n");
      scanf ("%[^\n]", &strn);
      p = &strn[0];
      length(p);
      getch();
      }
      void length(ptr)
      char *ptr;
      {
      int len=0;
      while (*ptr != '\0')
      {
      len++;
      ptr++;
      } printf ("Length of the string = %d\n", len);
      }


      Output:


      In the above example the base address of the array strn[ ] is passed to the function length() using the pointer variable p in the main(). The address is received in the function length() by the pointer variable ptr. Simple while loop is used in the function length() to advance the pointer ptr till the end of the string as we know that the string is terminated by a null (‘\0’) character. The contents of pointer are increased till a null character is encountered. The length of the string is printed in the function length() itself.
      Let us consider again the program to find the length of a string using pointers and functions. But in this we are returning back the value of length of the string back to the function main() through a return statement in function length() and the value sent back from the function is received by the variable len and it’s value is printed in the main().

      # include <stdio.h>
      # include <conio.h>
      void main ( )
      {
      char strn[100]; int len=0;
      int length();
      printf("Enter a string \n");
      scanf ("%[^\n]", &strn);
      len=length(&strn[0]);
      printf ("Length of the entered string is = %d\n",len);
      getch ( );
      }
      int length(ptr)
      char *ptr;
      {
      int ln=0;
      while (*ptr != '\0')
      {
      ptr++;
      ln++;
      }
      return(ln);
      }


      output:


      Note:
      Instead of a separate pointer variable p in the function main() we are directly sending the address of the first element of the array to the function length in the function call itself.

      Let us consider again another program to find the length of the string. In this program the length of the string is printed in the main() function itself. Here both the arguments passed to function length() are pointers.

      # include<stdio.h>
      # include <conio.h>
      void main ( )
      {
      char strn[100]; int len=0;
      void length();
      printf("Enter a string \n");
      scanf ("%[^\n]", &strn);
      length(&strn[0], &len);
      printf ("Length of the entered string is = %d\n",len);
      getch ( );
      }
      void length(ptr1, ptr2)
      char *ptr1;
      int *ptr2;
      {
      while (*ptr1 != '\0')
      {
      *ptr2 = *ptr2+1;
      ptr1++;
      }
      }


      Output:


      In the above program ptr1 and ptr2 are the pointers in the function length(), ptr1 pointing to the array variable strn[ ] and ptr2 is pointing to the variable len. Here the length is printed in the main() function and value of the variable len is not exclusively returned back to main() but it is available because the value of variable len is changed in the function length() by the statement *ptr2= *ptr2 + 1.

      Pointers and two-dimensional array:
      Elements 1 2 3 4 5 6 7 8 9 10
      Assumed Memory 150 152 154 156 158 160 162 164 166 168
      Consider a two dimensional array having five rows and two columns for example int test[5][2]; The elements and the assumed memory locations are given above.
      Since the memory is allocated continuously first four memory locations (150, 151, 152, 153 as each element is allocated two bytes because it is an integer array) correspond to first row, next four memory (154,155,156,157) locations correspond to second row and last four memory locations (166,167,168,169) correspond to last row. Thus two elements each are considered as one-dimensional array of two elements each.


      Consider the program given below it displays the address of each one dimensional array.
      # include<stdio.h>
      #include <conio.h>
      main ( )
      {
      int test [5][2] = { {1,2}, {3,4}, {5,6}, {7,8}, {9,10} }; int i;
      for (i=0; i<5; i++)
      {
      printf (“Subscript & address %d %u\n”, i, test[i]);
      }
      getch ( );
      }

      Output of the Program:


      When we are talking of pointers with 2 dimensional array, C language has a powerful capability of treating each row of a 2-dimensional array as a one dimensional array. This is a very important fact if we wish to access array elements of a two-dimensional array using pointers. Thus, the declaration int test [5][2] can be considered as setting a five one-dimensional array, each of which is a one-dimensional array of two elements long array. We refer to an element of one-dimensional array using a subscript. Similarly, if we can imagine test to be a one-dimensional array then we can refer to its 0th element as test[0], the next element as test[1] and so on. By writing like this you will get the address of 0th element, 1st element and so on.
      Analyzing the output of above program, the compiler knows that test is an integer array. So, each element of this array occupies 2 bytes. There are 2 elements in a row. So, each row takes 4 bytes. Thus each row starts 4 bytes further along from the last one as can be shown in the earlier shown memory map of the array.

      The compiler knows how many columns are there in the array since we have specified it in the array declaration. So it interprets test [0] at address 8698 and test [1] at 8702 and so on. So, now we have reached each individual row and we have to refer to the individual elements of this row. Suppose we want to refer to the element test [2][1] using pointer notation then, we know that test [2] will give the address 8706, the address of second one-dimensional array. So by writing 8706+1 we will get the address 8708. (Since it is not an ordinary arithmetic but pointer arithmetic). So it is now test [2]+1 will give us the address 8708 and value at this address can be obtained by * (test [2]+1). The above expression gives us the value 6, which is stored at that array location. This explanation is shown with the program given below.
      # include<stdio.h>
      #include <conio.h>
      void main ( )
      {
      int test [5][2] = {
      {1,2},
      {3,4},
      {5,6},
      {7,8},
      {9,10}
      };
      int i, j;
      for (i=0; i<5; i++)
      {
      for (j=0; j<2; j++) {
      printf ("Subscript and address %d %u", i, (test [i]+j));
      printf ("Element at address is= %d\n", * (test [i]+j));
      }
      }
      getch ();
      }

      Output of the Program:


      Note:
      The address allocated for the array is different in this because each time you execute a program the address allocated may be different. But the concept behind the explanation remains the same.


      Files << Previous     Next >>Structures and Unions

      Our aim is to provide information to the knowledge seekers.

      Support us generously

      comments powered by Disqus
Untitled Document
Untitled Document
Untitled Document
Untitled Document
Untitled Document
Untitled Document
Untitled Document
Untitled Document
Untitled Document
Footer1