Header Ads

Pointers



At the moment in which we declare a variable it is stored in the memory. We generally do not decide where the variable is to be placed - it is automatically done by the compiler and the operating system at runtime, but once the operating system has assigned an address there are some cases in which we may be interested in knowing where the variable is stored.

When we declare a variable in a program, the C compiler allocates a memory location with a unique address to store that variable. The compiler associates that address with the variable name. When the program uses the variable name, it automatically accesses the proper memory location. The Figure 1 shows this schematically. A variable named alpha has been declared and initialized to 25. We assume that the compiler has allocated storage at address 4905 for the variable and has associated the name alpha with the address 4905.

variable stored at a specific memory address

The memory address of the variable alpha (or any other variable) is a number and can be treated like any other number in C. If we know the address of a variable, we can create a second variable to store the address of the first variable. For example, let us declare a variable aptr to hold the address of alpha. The variable aptr is un-initialized - that is, the storage has been allocated for aptr, but its value is undetermined as shown in Figure 2.

pointer memory allocation

The next step is to store the address of the variable alpha in the variable aptr. Now, aptr contains the address of alpha. It indicates the location where alpha is stored in the memory. The aptr points to alpha or aptr is a pointer to alpha. This is shown in Figure 3.

variable storing memory address

To summarize a pointer is a variable that contains the address of another variable. Pointers are much used in C, partly because they are sometimes the only way to express a computation, and partly because they usually lead to more compact and efficient code, than can be obtained in other ways.)

pointer declaration:

                 data-type *pointername;

where data-type is any of valid data type and indicates the type of the variable that the pointer points to.  The asterisk (*) is the indirection operator, and it indicates that pointer-name is a pointer variable to type data-type. The following declaration, assignments and schematic diagrams illustrate the understanding of pointers.

variables and pointer

alpha and beta are ordinary integer variables and ptr is a pointer variable pointing to integer data type. If we execute the following output statements,

          printf("\n Address of alpha is %u", &alpha)
          printf("\n Address of beta is %u", &beta);
          printf("\n Address of ptr is %u", &ptr);

then, the output would be as follows (Note: These instance addresses are assumed):

           Address of alpha is 4905
           Address of beta is 4907
           Address of ptr is 4902

variable memory alloctaion

The variables alpha and beta are assigned 25 and 70 respectively
The statement, printf("alpha = %d, beta = %d", alpha, beta); //output: alpha = 25, beta = 70
 
pointer storing memory of variable

We cannot do anything with the pointer until we assign the address of a variable. By using the address operator (&, ampersand), we can initialize the pointer with the following statement.

                  ptr = α            /* Address of alpha is assigned to pointer, ptr */

After the initialization, ptr points to alpha. Then, the statement: printf("%u", ptr); prints the address of variable, alpha- that is, 4905. When the indirection operator (*, asterisk) precedes the name of the pointer, it refers to the value of the variable pointed to. The following two statements print the same output – is, 25.

                  printf("%d", alpha);        /* prints 25 */
                  printf("%d", *ptr);         /* prints 25 */

Accessing the contents of a variable by using a pointer to the variable is called indirect access or indirection. The following schematic diagram illustrates this indirection.

indirect access by pointer
If we have a pointer named ptr that has been initialized to point to the variable alpha, then

(a) *ptr and alpha both refer to the contents of alpha (that is. 25)
(b)   ptr and &alpha refer to the address of alpha (that is, 4905).

Example 1: A program that demonstrates the basic concepts of pointers. 

Code

#include <stdio.h> 
void main() 
{ 
   int alpha = 25, beta = 70;    /*Declare and initialize two int variables */
   int *ptr; 		        /*Declare a pointer to int */ 
   ptr = α                 /* Initialize ptr to point to alpha */ 
   printf("\n 1. Direct access, alpha = %d", alpha); /*Access alpha directly */ 
   printf("\n 2. Indirect access, alpha = %d", *ptr); /* Access alpha indirectly */ 
   printf("\n 3. Address of alpha = %u", &alpha); /*Display address of alpha */
   printf("\n 4. Address of alpha = %u", ptr);        /* Display address of alpha */ 
    alpha = alpha + 10;                                          /*Change value of alpha */ 
    printf("\n 5. Changed value of alpha = %d", alpha); /* Access alpha directly */ 
    printf("\n 6. Changed value of alpha = %d", *ptr): /*Access alpha indirectly */ 
    ptr = β                                                         /* Initialize ptr to point to beta */
    printf("\n 7. Address of beta = %u", &beta): /* Display address of beta */ 
    printf("\n 8. Address of beta = %u", ptr):  /* Display address of beta */ 
    printf("\n 9. Direct access, beta = %d", beta): /* Access beta directly */ 
    printf("\n 10. Indirect access, beta = %d". *ptr); /* Access beta indirectly */ 
}
If we execute this program, then the following output will be displayed (The addresses reported for alpha and beta might not be 4905 and 4907 on the system these are only instance addresses. They may be different in different occasions. The program and following output may be keenly observed):

     1. Direct access, alpha = 25
     2. Indirect access, alpha = 25
     3. Address of alpha = 4905
     4. Address of alpha = 4905
     5. Changed value of alpha = 35
     6. Changed value of alpha = 35
     7. Address of beta = 4907
     8. Address of beta = 4907
     9. Direct access, beta = 70
     10. Indirect access, beta = 70

Different variable types occupy different amounts of memory. Commonly, an int takes two bytes, a float four bytes, a char one byte, and so on. Each individual byte of memory has its own address, so a multi- byte variable actually occupies several addresses. The address of a variable is actually the address of the first byte it occupies.

Example 2: A program, which computes the factorial of a number using pointers. 

Code

#include <stdio.h> 
void main() 
{ 
   int n, *pn; 
   long fact = 1; 
   pn = &n;              /* Assign address of n to pointer pn */ 
   printf(" Enter n = "); 
   scanf("%d", pn)      /* Read n */ 
   for(; *pn>0; --*pn) 
      fact = *pn * fact; 
   printf(" Factorial = %ld", fact); 
}
The pointer pn is initialized by the address of n. So, the pointer variable pn points to the address of n. *pn refers to the contents of n. If we have read n = 6. then *pn refers to 6. In the for-loop, the contents of n is decremented by 1 (--*pn). The factorial comp  utation is carried out while the contents of n is greater than zero

The for-loop is terminated when the condition *pn > 0 is false (*pn = 0).

Passing Pointers as Arguments to Functions

When a pointer is passed as an argument to a function, the address of a variable is passed to function. The contents of that address can be accessed, either within the function or within the call function. Any change that is made to the contents of the address (variable) will be reflected in both functions calling and called functions. Thus, the use of a pointer as an argument permits corresponding data item to be changed globally from within the function. In the function definition asterisk (*) must precede each one of the formal arguments. The function prototypes are written in same manner. The use of pointer argument is illustrated in the following example.

Example 3: A simple program that illustrates the difference between ordinary arguments (pass-by-value) and pointer arguments (pass-by-reference).

Code

#include <stdio.h> 
void main() 
{ 
   int alpha = 25; 
   void func 1( int alpha); 
   void func2( int *a ); 
   printf("\n Before calling func1: alpha = %d", alpha): 
   func1(alpha); 
   printf("\n After calling func1: alpha = %d", alpha): 
   func2(&alpha); 
   printf("\n After calling func2: alpha = %d", alpha): 
}

void func1 (int alpha) 
{ 
   alpha = 100; 
   printf("\n Within func1: alpha = %d", alpha): 
   return; 
} 
             
void func2( int *a ) 
{ 
   *a = 45; 
   printf("\n Within func2: a = %d", *a): 
   return; 
}
The first function receives an integer variable (alpha = 25) as an argument. The value is changed t0 100 within func1 ( ). The new value is not established in main(), because the argument has been passed by and any change to the argument is local to the function. The second function receives a pointer to  integer  variable as its argument (*a). The formal argument is identified as a pointer (*)

Within func2(), the contents of the pointer address is changed to 45. Since the address is recognized in both func20) and main(), the modified value is reflected in both. The following is the output of this program:


       Before calling func1: alpha = 25

       Within func1: alpha = 100

       After calling func1: alpha = 25

       Within func2: a = 45

       After calling func2: alpha = 45


Pointers and Arrays


There is a strong relationship between pointers and arrays. Any operation by arrays can also be done with pointers. An array uses subscripts and is evaluated as a constant pointer. When an array is declared, the compiler allocates a base address (address of first element) and sufficient memory storage to contain all elements of the array in contiguous memory locations. The pointer version will in general be faster.


The following array declaration defines an array a of size 10, that is, a block of 10 consecutive elements named a[0], a[1], a[2], . . ., a[9].


              int a 10];


Let us assume that an int takes two bytes of memory, also the base address of the array is 9700 (Note: all addresses are shaded). This means that the address of a[0] is 9700. Since, an int takes two bytes of storage space in the memory, the next element of the array, a[1] will be located at 9702. All elements of the array are located adjacent to each other. The data elements are 10, 20, 30, . . ., 45, 55 as shown in the following Figure 4. 


integer array of size 10

The notation a[i] refers to the ith element of the array. If pa is a pointer to an integer declared as

int *pa;

then the assignment                pa = &a[0];


sets pa to point to first element of a; that is, pa contains the address of a[0], base address of a.


pointer storing array address

The assignment, x = *pa; will copy the contents of a[0] into x.


If pa points to a particular element of an array, then pa+1 points to the next element. For example, pa points to a[5], then pa-1 points to a[4]. Thus, if pa points to a[0], then *pa refers to the contents of a[( *(pa+1) refers to the contents of a[1], and so on.

accessing array by pointer

The meaning of "adding 1 to a pointer" is that pa+1 points to the next element and pa+i points to the element beyond pa.


The correspondence between indexing and pointer arithmetic is very close. After the assignment: pa &a[0]; (or pa = a;), pa and a have identical values. A reference to a[i] can also be written as *(a+i). evaluating a[i], C system converts it to *(a+i) immediately; the two forms are equivalent. It follows th &a[i] and (a+i) are also identical. pa[i] is identical to *(pa+i). The following examples illustrate the use pointers in processing arrays.


Example 4: A simple program, which reads in array elements and finds the sum of the array elements using pointers.

Code

#include <stdio.h> 
void main() 
{ 
  int a[10], *pa, i, n = 10, sum = 0; 
  pa = &a[0]; /* Assign base address of array to pointer */ 
  for(i = 0; i < n; i++) 
  { 
    scanf("%d", pa+i); /* Alternately, scanf("%d", &pa[i] ); */ 
  } 
  for(i = 0; i < n; i++ ) 
  { 
    sum = sum + *(pa+i); /* Alternately, sum = sum + pa[i]; */ 
  } 
  printf("\n sum = %d", sum); 
} 


Operations on Pointers - A pointer is also one of the data types and is different from a standard data type It does not have a data type of its own. It takes the data type of the variable to which it is pointing. For example, if we need a pointer to point to an integer variable, then we declare as follows.


               int *x;    /* x is a pointer variable pointing to integer variable */


As possible with other data types, all kinds of operations are not allowed on pointers. The following two operations are permitted on pointers.


(a) Pointer arithmetic

(b)Pointer comparison


Pointer arithmetic - We can only perform addition and subtraction on pointers. We can also name this as address arithmetic. Addition operations on pointers are similar to the operation where we used pointers to address the different elements of an array. We consider the following example.


int x, *px; /*Declaration of an integer variable, integer pointer */

px = &x; /* Assign address of variable x to the pointer px */

x = 25;  /* Assign 25 to integer variable */


Assume the memory address of the variable x is 5003. If the statement: px = px + 3; is executed, then pointer px will contain 5009 (assuming that an int takes two bytes of memory storage). The question mark (?) indicates some garbage value. 


illustration of pointer arithematic


We can write expressions such as ++px, --px, (px + 2), (px + k), and (px-k), where k is an integer variable. Each expression will represent an address that is located some distance from the original address represented by px. The following are some of the valid arithmetic expressions:


      ++*px;                             /* increments the value of variable x by 1

      --*px;                              /* decrements x by 1 */

      *px + 10;                    /* add 10 to x */

      *px * 10 + x;              /* this expression is same as x * 10+x */


Pointer comparison - Two pointers are compared in a relational expression. However, this is possible if both the pointers are pointing to variables of the same data type. We illustrate the pointer comparison by the following example.


            int x, y, *px. *py;     /* Declaration of integer variables and pointers */

            px = &x:                  /*Assign address of variable x to the pointer px */

            py = &y;                  /*Assign address of variable y to the pointer py */

            x = 25; y = 100;


following Figure 6 illustrates the comparison of pointers px and py. We assume that memory address of variable x is 8686 and that of y is 8688.


pointer comparison

The following table provides examples of pointers comparison.

Table 1 Pointers comparison 

table of pointer comparison

The following table summarizes pointer operations.

Table 2 Pointer operations

pointer operations

Pointers and Strings - One way to allocate and initialize a string is to declare an array of characters as follows:
char str[] = "Info Tech";

We could accomplish the same thing by declaring a pointer to type character:
char *cptr = "Info Tech";

Both declarations are equivalent. In each case, the compiler allocates enough space to hold the string along with its terminating null character.
A pointer pointing to a string contains the base address of the character array and entire array (or a part of the array) can be accessed using this pointer. The following examples will clarify the association of pointers with strings (Note: additional programs are given in Exercises at the end of this chapter): 

Example 5: A program, which illustrates use of pointers with strings

Code

void main() 
{ 
    char str1[] = "INFO TECH"; 
    char str2[] = "Java and Internet"; 
    char *cptr;          // a pointer to type char 
    puts(strl);          // displays INFO TECH 
    puts(str2);         // displays Java and Internet 
    cptr = strl;         // base address of strl is assigned to pointer cptr 
    puts(cptr);         // displays INFO TECH 
    cptr = cptr + 5;  // advances pointer to next 5 locations or cptr = &str1[5];
    puts(cptr);        // displays TECH 
    cptr = str2;       // assigns base address of str2 to pointer cptr 
    puts(cptr);       // prints Java and Internet 
    cptr = cptr + 9; // advances cptr to next 9 locations 
    puts(cptr);      // displays Internet 
}
The output of this program is:
       INFO TECH
       Java and Internet
       INFO TECH
       TECH
       Java and Internet
       224
       Internet

Example 6: A program, which determines the length of a string using pointers.

Code

#include <stdio.h> 
void main() 
{
  char str[20]= "C++ and Java"; 
  char *cptr; int strlen = 0; 
  cptr = str;                        /* assigns base address of str to pointer cptr */ 
  for(; *cptr != NULL; cptr++) strlen++;
  printf("String length = %d", strlen); 
}
After assigning the base address of str to cptr, cptr contains the address of first character of the string. *cptr points to the first character of the str. There is no initial expression in for-loop. The expression cptr++ advances to the next address location and *cptr points to the next character of the str. Finally, the for-loop will be terminated, because *cptr points to null character. This program displays
String length = 12

Dynamic Memory Allocation

The statement:
                              int arr[100];

allocates memory space to hold a maximum of 100 elements of type integer - this is called static memory allocation. This method of allocating space for array storage is fine when we know what we want while writing the program. What if the program has varying array storage needs, depending on user input or other factors that are unknown when we are writing the program? We use the malloc() function to allocate memory space during run-time. The process of allocating memory to store variables as and when required at run-time is known as dynamic memory allocation (DMA).

The malloc() function is one of the memory allocation functions in C. It allocates a requested number of bytes from the free pool of memory (heap) and returns a pointer to a block of contiguous memory of the size specified. The syntax is:

             <pointer>= (<cast-type>*) malloc (<number of bytes to be allocated>);

The pointer is the name of a pointer of type cast-type, which points to the first byte of the memory block of size as number of bytes to be allocated. If the memory allocation is not successful, it returns a NULL pointer. For example, the following declaration and statement allocate the required memory space. The Figure 8 illustrates the memory block allocated from the memory heap. We assume an integer takes two bytes and numbers shown in memory cells are instance addresses.

                  int *arr;                                               /* arr is a pointer pointing to integer type *
                  arr = (int*)  malloc( 5* sizeof(int));   /* 10 bytes memory is allocated */

malloc memory allocation

The header file, stdlib.h contains memory management functions: malloc(), calloc(), free(). and realloc().
These functions are used to allocate and free memory during program execution. The following examples illustrate the dynamic memory allocation.

Example 7: The following program allocates a required memory block using malloc() function, displays the memory addresses, reads the data elements, and prints the values.

Code

#include <stdio.h> 
#include <stdlib.h> 
void main() 
{ 
  int *arr, n, i; 
  printf(" Enter Number of elements, n = "); 
  scanf("%d", &n); 
  arr = (int*)malloc(n* sizeof(int));     /*Allocate memory space */ 
  if(arr == NULL)    			 /*Could not allocate memory space */ 
  { 
    printf(" Cannot allocate memory space");
    exit(1);  			/* Exit from the program */ 
  } 
  printf(" Allocated memory addresses: "); 
  for(i=0; i<n; i++)    			/* Display memory addresses */ 
  { 
    printf("%u", (arr+i)); 
  } 
  printf("\n Input data elements: "); 
  for(i=0; i<n; i++)  			/* Input data items */
  { 
    scanf("%d", (arr+i) ); 
  } 
  printf("\n Display of data elements: "); 
  for(i=0; i<n; i++)		/* Display data items */ 
  {
    printf("%d", *(arr+i) ); 
  } 
  free(arr);                       /*Release memory space */
} 
If we execute the program by entering, n = 5, the following output will be generated.
Enter Number of elements, n=5
Allocated memory addresses: 404 406 408 410 412
Input data elements: 10 20 30 40 50
Display of data elements: 10 20 30 40 50

When we are dynamically allocating memory for variables at run time, the memory is not automatically released to the system. Using the free() function, we release a block of memory that was allocated.

The syntax of free() function is
                                       free(<pointer>);

The pointer, which is pointing to the memory block that was returned by either malloc() or calloc() function calls.

Example 8: Here is an example to allocate required memory space to ordinary variables number and fact using malloc() function. This program computes the factorial of a number. 

Code

#include <stdio.h> 
#include <stdlib.h> 
void main() 
{ 
  int *number; long *fact; 
  number = (int*) malloc(sizeof(int));    /*Allocate memory to number */ 
  fact = (long*)malloc(sizeof(long));     /*Allocate memory to fact */ 
  printf(" Enter number = ");
  scanf("%d", number);    		    /* Input number */ 
  for(*fact = 1; *number > 0; --*number) 
    *fact=*fact *  *number;
  printf(" Factorial of number = %ld", *fact); 
  free(number); 
  free(fact); /* Release memory allocated to number and fact*/ 
}
Output -
   Input: Enter number = 6
   Output: Factorial of number = 720

calloc() function is normally used to allocate memory during run-time for storing derived data types such as arrays and structures. It allocates multiple blocks of memory, each block being of the same size and then sets all the bytes of memory in the block to zero.

The syntax is

<pointer>= (<cast-type>*) calloc (<number of blocks>, <size of block>);

For example, we can replace the malloc() function in the Program 10-11 with calloc() function.

arr = (int*) calloc(n, sizeof(int) );

realloc() function reallocates memory space to increase or decrease the size of allocated memory. After allocating memory to variables at run-time, there may be a need to change the size of allocated memory block. The general form is

<pointer> = realloc (<pointer>, <<new memory size>);

The pointer is the name of a pointer, which points to the first byte of the memory block that was allocated using either malloc() or calloc() function. The new memory size that is to be re-allocated may be less or more of the original size. The new block may or may not begin at the same location of the old block.

Arrays of Pointers

Since pointers are variables themselves, they can be stored in arrays just as other variables can. An array of pointers can be made of any valid data type. An array of integer pointers is declared like any other integer array. A two-dimensional array can be declared as one-dimensional array of pointers like:

<data-type> *<array-name> [<array-size>];

Suppose arr is a two-dimensional integer array (3 rows x 5 columns), we can define arr as a one- dimensional array of pointers.

int *arr[3];

arr[0] points to the beginning of first row, arr[1] points to the beginning of second row, and arr[2] points to the beginning of third row. The number of elements within each row is not explicitly specified. The expression *(arr[2]+3) accesses the element arr[2][3]

array of pointers

Example 9: This example is meant for finding the sum of elements of a two-dimensional array (matrix)using array of pointers

Code

#include <stdio.h> 
#include <stdlib.h> 
void main() 
{ 
  int *arr[10]; 	/* One-dir: array of pointers of having a max of 10 rows */ 
  int m; 		 /* Number of rows */ 
  int n; 		 /* Number of columns */ 
  int i, j, sum = 0; 
  printf(" Enter number of rows & columns = "); 
  scanf("%d %d", &m, &n); 
  for(i=0; i<m; i++)		 /* Allocate initial memory */ 
  { 
    arr[i] = (int*)malloc(n* sizeof(int)); 
  } 
  for(i=0; i<m; i++)	/* Input array elements row-wise */ 
  { 
    printf("\n row %d: ", i); 
    for(j=0; j< n; j++) 
    { 
      scanf("%d", (arr[i]+j) ); 
    } 
  }
  for(i=0; i<m; i++) 
  { 
    printf("\n"); 
    for(j=0; j<n; j++) 
    { 
      printf("%4d", *(arr[i]+j) );	 /*Print array elements row-wise */ 
      sum = sum + *(arr[i]+j); 	  /*Accumulate sum of elements */ 
     } 
   }
printf("\n sum of elements = %d", sum ); 
}
The input/output of this program is as follows (numbers in italics are user's data entry):

Enter number of rows & columns = 25
row 0: 12345
row 1:6 7 8 9 10
1 2 3 4 5
6 7 8 9 10
sum of elements = 55

Example 10: This example illustrates the application of array of character pointers. The program reads the names into an array of character pointers, *name[i], arranges the names in alphabetical order, and prints the sorted names.

Code

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
void sort(char *name[], int n); 	/* Function prototype */
void print(char *name[], int n);	/*Function prototype */ 
void main() 
{ 
  char *name[10]; 	/* Maximum of 10 names */ 
  int i, n; 
  printf("How many names? "); 
  scanf("%d", &n); 	/* Input required number of names */ 
  for(i=0; i<n; i++) 
  {
    fflush(stdin); 		/* Clear input buffer */ 
    name[i] = (char*)malloc(26); /* Allocate memory space of 26 bytes */ 
    gets(name[i]); 		/* Read a name */ 
  } 
  sort(name, n); 	/* Call sort function to sort names */ 
  print(name, n);		 /*Print sorted names */ 
} 
void sort(char *name[], int n) 	/* sort function */ 
{ 
  int i, j; char *tmp; 
  for(i=0; i<n; i++) 
  { 
    for(j=0; j<n; j++) 
    { 
      if(strcmp(name[j], name[i]) > 0) 
      { 
        tmp = name[i]; 	/* Swap name[i] and name[j] */
        name[i] = name[j]; 
        name[j] = tmp; 
      } 
    } 
  }
 return;  
} 

void print(char *name[], int n)	 /* print function */ 
{ 
  int i; 
  printf("\nSorted names:\n"); 
  for(i = 0; i < n; i++) 
  { 
    puts(name[i]); 
  } 
  return; 
}
This program has generated the following input/output:

How many names? 5

Ram Babu
Kiran Kumar
Aswani Nachappa
Yahoo Krishna
Richard Gere

Sorted names:
Aswani Nachappa
Kiran Kumar
Ram Babu
Richard Gere
Yahoo Krishna

Pointers to Functions - Pointers to functions offer another way of calling functions. We might be thinking "how can we have a pointer to function?" A pointer to a function holds the starting address of a function, which is its entry point. A function itself is not a variable, but it is possible to define pointers to function which can be assigned, placed in arrays, passed to functions. returned by functions, and so on. Why use pointer to a function? It provides a more flexible way of calling a function. The general form of the declaration of a pointer to a function is as follows:

<type> (function-pointer)(<parameter-list>);

Here are some examples

int (*func1)(int a); /* func1 is a pointer to a function that takes one int argument and returns a type int
int (*func2)(float x, int a);
void (*func3)(void);

It is important to enclose the name of the function-pointer within parentheses. The precedence of the indirection operator (*) has a relatively lower than the parentheses surrounding the parameter-list.

The declaration: int *func1 (int a); without first set of parentheses, declares func] as a function that returns a pointer to an integer - that is, a function returning pointer and not a variable pointing to the firs instruction of the function in the memory. We discuss a function returning a pointer in the next Section 10.10.

Function returning a Pointer

A function can return a pointer to the calling function. The indirection operator (*) is used in function declaration as well as in function definition. The general form of the declaration is

<type> *<function> (<argument-list>);

This statement declares function that returns a pointer to type. The following example illustrates the concept of a function returning a pointer.

Example 12: If we want to add a new item to the array at the given location or delete an item from the array, then we will have to find (locate) the required position of the item in the array. In this program, the find() function returns the location address of the array by searching the item in the array. If search is successful, the function returns the address (loc) otherwise returns NULL.

Code

#include <stdio.h> 
int *find(int[], int, int); /*Function prototype */ 
int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 
void main() 
{ 
  int *loc, item; 
  scanf("%d", &item);
  loc= find(arr, 10, item); 
  if (loc != NULL) 
    printf("Item %d found in the array", *loc); 
  else 
    printf("Item %d not found in the array", item); 
}
int *find(int x[], int n, int item)  /* Function definition */ 
{ 
  int i; 
  for(i = 0; i < n; i++) 
    if( item = x[i] ) return(&x[i]); 
  return(NULL); 
}
Pointers to Pointers - A pointer is a numeric variable with a value that is the address of another variable. We declare a pointer using the indirection operator (*). For example, the declaration: int *ptr; declares a pointer named ptr that can point to an integer variable. We then use address operator (&) to make the pointer point to a specific variable of the integer type. Assuming that numb has been declared as an integer variable and initialized to 25 (int numb = 25;), the statement: ptr = &numb; assigns the address of numb to ptr and makes ptr point to numb. Then, *ptr accesses the contents of numb (i.e., 25).

Because a pointer is itself a numeric variable, it is stored in the computer's memory at a specific address. Therefore, we can create a pointer to pointer, a variable whose value is the address of a pointer. Here is a program to illustrate a pointer to a pointer.

Code

#include <stdio.h> 
void main() 
{ 
  int *ptr, **pp, numb = 25; 
  printf("\n Address of numb = %u", &numb); 
  printf("\n Address of ptr = %u", &ptr); 
  ptr = &numb; 		/* Assign the address of numb to ptr*/
  pp = &ptr;              /* Assign the address of ptr to pp */ 
  printf("\n\n ptr pointing to numb (address of numb) = %u", ptr); 
  printf("\n pp pointing to ptr (address of ptr) = %u", pp); 
  printf("\n\n ptr pointing to numb (contents of numb) = %d", *ptr); 
  printf("\n pp pointing to ptr (contents of numb) = %d", **pp); 
 }
A double indirection operator (**) is used when declaring a pointer to a pointer. We also use operator when accessing the pointed-to variable (numb) with a pointer to a pointer. The last printf statement of the preceding Program 18 displays 25, the value of numb. The program has generated the following output: (8890 and 8894 are the instance addresses)

Address of numb = 8890
Address of ptr = 8894
ptr pointing to numb (address of numb) = 8890
pp pointing to ptr (address of ptr) = 8894
ptr pointing to numb (contents of numb) = 25
pp pointing to ptr (contents of numb) = 25

Declaring and using a pointer to a pointer is called multiple indirection.

Call by Value - While passing parameters by call by value, Xerox copy of original parameter is created and passed to the called function. Any updation made inside the method will not affect the original value of variable in calling function. Example- Call by Value

Code

#include<stdio.h> 
#include<conio.h> 
void swap(int numl, int num2) 
{
 int t=num1; 
 num1=num2; 
 num2=t; 
}
void main() 
{ 
 int n1,n2; 
 printf("Enter any two numbers"); 
 scanf("%d%d",&nl,&n2); 
 printf("Before swapping\n"); 
 printf("n1=%d\tn2=%d\n",nl,n2); 
 swap(n1, n2); 
 printf("After swapping\n"); 
 printf("n1=%d\tn2=%d\n",nl,n2); 
 getch(); 
} 
Output -
Enter any two numbers
11
22
Before swapping
nl=11 n2=22
After swapping
n1=11n2=22 

In the above example, num1 and num2 are the original values and Xerox copies of these values is passed to the function and these values are copied into the number1 and number2 variable of swap function respectively.

As their scope is limited to only function so they can not alter values inside the main function

call by value

Call by reference - While passing parameter using call by reference, we are actually passing the actual address of the variable to the called function. Any updation made inside the called function will modify the original copy since we are directly modifying the content of exact memory location. Refer following Ex

Code

#include<stdio.h> 
void swap(int *numl, int *num2) 
{ 
  int t=*numl; 
  *num1=*num2; 
  *num2=t; 
}
void main() 
{
  int nl,n2; 
  printf("Enter any two numbers"); 
  scanf("%d%d",&n1,&n2); 
  printf("Before swapping\n"); 
  printf("n1=%d\tn2=%d\n",nl,n2); 
  swap( &n1, &n2); 
  printf("After swapping\n"); 
  printf("n1=%d\tn2=%d\n",nl,n2); 
} 
Output 
Enter any two numbers
11
22
Before swapping
n1 = 11      n2 = 22
After swapping
n1=22       n2=11

Summary 

call by value and call by reference summary

Call by value, Call by reference:

call by value and call by reference difference

Advantages of Pointers:

1. The pointer saves the memory space.
2. Execution time with pointer is faster because data is manipulated with the address i.e. direct access to the memory location.
3. The memory is accessed efficiently with pointers. The pointer assigns the memory space dynamically. That leads you to reverse a specific byte in memory.
4. Pointers are used in data structure. They are useful for representing two dimensional and multidimensional array.
5. In C, a pointer declared to a base class could access the object of a derived class whereas the pointer to a derive class cannot access the object of a base class.
6. The compiler will generate the error message cannot convert A* to B* whereas A is a base class and B is derived class.

Short Questions

1) What are pointers? Why they are important?

A pointer is a memory variable that stores a memory address. Pointer can have any name that is legal for other variable and it is declared in the same fashion like other variable but it is always denoted by ‘ * ’ operator.

2) Explain features of pointers.

1) Pointers save the memory space.
2) Execution time with pointer is faster because data is manipulated with the address i.e. direct access to memory location.
3) The memory is accessed efficiently with the pointers. The pointer assigns the memory space and it releases. Dynamically memory is allocated.
4) Pointers are used with data structures. They are useful for representing two-dimensional and multi-dimensional arrays.

3) Explain pointer of any data type that requires four bytes.

A memory address of any variable is an unsigned long integer. It occupies 4 bytes. Hence, pointer of any data types that requires four bytes.

4) Explain use (*) indirection operator.

The (*) indirection operator is used to indicate pointer variable.

5) Explain effect of ++ and - operator with pointer of all data type.

The (++) increment operator when applied with pointer it indicates next memory location of its type. When (--) decremented it indicates previous memory location of its type.

6) Explain relation between array and pointer.

The array name itself is a pointer. The array name points to first element of the array.

7) Why addition of two pointers is impossible?

The pointer holds address of another variable. Hence, addition of addresses is not possible.

8) Which are the possible arithmetic operations with pointers?

Arithmetic operations on pointer variables are also possible. Increment, decrement, prefix, & postfix operations can be performed with the pointers. The effect of these operations are shown in the below given table. 

arithematic operations with pointers

Table Pointer and Arithmetic Operation

From the above table we can observe that on increment of the pointer variable for integers the address is incremented by two i.e. 4046 is original address and on increment it's value will be 4048 because integers require two bytesSimilarly, for characters, floating point numbers and long integers requires 1, 4 and 4 bytes respectively.

9) How will you recognize pointer to pointer? What the number of '*'s indicates.

The pointer of pointer is preceded by '**' in declaration.

10) How strings are stored in pointer variables? Is it essential to declare length?

The strings are stored in continuous memory locations. It is not essential to declare length.

Pointer statements

int(*data) [10];
It implies that data is only one pointer and it is a pointer to an array of 10 integers.

int *data[10];
It implies that there are 10 pointers and each of these is a pointer to an integer.

float *fun ()
fun is a function that returns pointer to a float variable.

float (*fun) ()
fun is a pointer to a function returning float.

float *(*fun) ()
fun is a pointer to a function returning pointer to float. 

No comments

Powered by Blogger.