Pointers – Vows and Concerns

One great feature managed environments such as java and .net claim is the role and use of garbage collector. In this article we will be looking and the main pointer vows of C/C++ which acted as motivation for evolution of managed environment and garbage collection. In this section we will talk about

  • Wild Pointer
  • Dangling Pointer
  • Memory Leak

Wild Pointer

Wild pointers are pointers that points to the wild; that is where we don’t know. Essentially ever pointer that is created but not initialised will be wild pointer.

   1:  void main()
   2:  {
   3:      int x=5;
   4:   
   5:      int *p1=&x;     //ok. pointer properly initialised
   6:      int *p2=NULL; //ok. we still know pointer points to nothing
   7:      int *p3;             //*** Wild Pointer ***
   8:   
   9:      *p1=20; //it will change the value of x. 
  10:   
  11:      *p2=20; // It will try to set 20 to NULL. Probably program will terminate. No real damage done
  12:   
  13:      *p3=0; // 20 will be set to wild. dont know where and what will happen now. change in value of x can't be ruled out.
  14:   
  15:  }
 
 

 

In the example above pointer p1 is properly initialised to the address of variable x. Thus *p1=20 will predictably change the value of x from 5 to 20.

In the second case pointer p2 is initialised to NULL. This again is a conscientious decision that p2 points to nothing. *p2=20 in most cases will cause program to terminate and no real data loss of damage is likely. Better, it gives us a clue to find out that we worked with a NULL pointer. In some compiler the program continues to work fine and we get a message of Null Pointer Assignment only when program terminates.

Now let us turn to the third case pointer p3. We didn’t mentioned where it will point – so it will point to some unknown, random and wild memory location. So we call it wild Pointer. Now *p3=0 will be risky in the sense that on one hand we don’t know where it points and on the other hand compiler too doesn’t know that we don’t know this vital fact. So it will do nothing to stop assignments and 20 will be placed in the wild. Now this wild can be anything – It could be one of the program variables; in which case later will be over-ridden giving unexpected result of behaviour. Think what will happen if p3 accidentally points to x?

It could be one of the code block address; in which case the program is likely to crash.

It could be pointing to just nothing; in which case no real damage will happen except that you will just miss out a good lesson in your programming career.

So moral of the story avoid being wild when coding.

 

Dangling Pointers

Dangling pointers, on other hand, are pointers, which once were pointing to something valid location, but of late it is no more valid. The most likely scenario goes like this:

We used a pointer to refer to a dynamic memory and later knowingly and accidentally the memory is freed. Technically the pointer used with free is now termed as dangling pointer. However, dangling pointers becomes more troublesome when we have more than one pointer to the same memory location. The memory location got freed by one of them and the second is totally ignorant of the fact. Obviously this is normally a product of bad programming. The code below refers to such a case.

   1:  #include <stdio.h>
   2:  #include <stdlib.h>
   3:   
   4:  int * allocate(int size);
   5:  void fill(int *array, int size, int value);
   6:  void show(int *array, int size);
   7:  int sum(int *array, int size);
   8:   
   9:  void main()
  10:  {
  11:      int *list1,*list2;
  12:   
  13:      list1=allocate(10); //books a new memory
  14:      fill(list1,10, 100); //filll list of 10 items with 100 each
  15:      show("list1:",list1,10);
  16:   
  17:      printf("sum of values in list1 is %d\n", sum(list1,10));
  18:      //sum function accidently frees the memory pointed by list1
  19:      //now list1 no more refers to a valid location
  20:      //worst is main never knows list1 is dangling
  21:   
  22:   
  23:  
  24:      list2=allocate(10); //Need a new memory location
  25:      //since memory location that once belonged to list1 is free
  26:      //it can be reallocated to list2
  27:      //if this be the case list1 now points to memory that belong to
  28:      //list2
  29:      printf("filling list2 with 200...\n");
  30:      fill(list2, 10, 200); //list2 now contains 200 in all 10 locations
  31:   
  32:      printf("filling list1 with 1000...\n");
  33:      fill(list1, 10, 1000); //list1 now fills 1000 to all 10 locations
  34:      //but list1 no more is assoicated with a valid memory location
  35:   
  36:      show("List2:",list2,10);
  37:   
  38:      //The expected output it 10 times 200. The actual may be 10 times 1000
  39:      //if list2 and list1 are pointing to the same location
  40:   
  41:   
  42:   
  43:  }
  44:   
  45:  int * allocate(int size)
  46:  {
  47:      int *p= malloc(size*sizeof(int));
  48:      return p;
  49:  }
  50:   
  51:   
  52:  void fill(int * array, int size, int value)
  53:  {
  54:      int i=0;
  55:      for(i=0;i<size;i++)
  56:          array[i]=value;
  57:  }
  58:   
  59:  int sum(int *array, int size)
  60:  {
  61:      int tot=0;
  62:      int i;
  63:      for(i=0;i<size;i++)
  64:          tot+=array[i];
  65:   
  66:      free(array); //sum frees array. Bad coding
  67:                  // makes pointer dangling
  68:                  // the caller is not aware of this
  69:                  // bad code piece
  70:      return tot;
  71:  }
  72:   
  73:  void show(char *prompt,int *array,int size)
  74:  {
  75:      int i=0;
  76:      printf(prompt);
  77:      for(i=0;i<size;i++)
  78:          printf("\t%d",array[i]);
  79:   
  80:      printf("\n");
  81:  }
 

 output of dangling pointer program

 

In the code above we allocated memory for 10 integers and pointed it with pointer called list1. Next we filled it with value of 100 each and displayed the content of it. So far the code works fine. But next when we called sum function on line number 17, the function freed the memory (design wise it was not supposed to do this).

Next we allocated a new set of memory for another 10 integers and pointed it with a pointer called list2. Although it is a new request, it is likely that compiler will allocate me the very same memory which is recently occupied by list1 and which was subsequently freed by sum function. While this behaviour really depends on compiler, the behaviour is successfully reproduced using Turbo C 3.0 and Visual Studio.Net 2008.

Now the memory technically belongs to list2; but list1 also points to the same memory. At line number 30 list2 fills 200 to its memory location. Then at line 33, list1 fills a value 1000 to its memory location. But now both list2 and the dangling pointer list1 are pointing to the same memory location. Thus effectively the values for list2 will change to 100 without providing any logical explanation.

Memory Leak

Another common pointer mistake is allocating the memory and then forgetting to free it. If a memory is allocated and we no more need it, in C/C++ it is our responsibility to free the same. Compiler will not do it for me. And if we choose to ignore it too, we will end of making the memory perfectly allocated and perfectly useless. This is memory leak. Consider the code below:

   1:  #include <stdlib.h>
   2:  #include <stdio.h>
   3:   
   4:  #define BYTE char
   5:   
   6:  void swap(void * p, void *q, int size);
   7:  void show(char *prompt,void *p, int size);
   8:   
   9:  void main()
  10:  {
  11:      int x[]={2,3,5,2,9};
  12:      int y[]={4,5,1,1,8}
  13:  
  14:      swap(x,y, sizeof(x));
  15:  
  16:      show("x=",x,5);
  17:      show("y=",y,5);
  18:  }
  19:   
  20:  void swap(void *p,void *q, int size)
  21:  {
  22:      BYTE *t=malloc(size);
  23:      memcpy(t,p,size);
  24:      memcpy(p,q,size);
  25:      memcpy(q,t,size);
  26:  
  27:      return; //we allocated memory for t but forgot to free it
  28:                    //its a memory leak
  29:  
  30:  }
  31:   
  32:  void show(char *prompt,int *p, int size)
  33:  {
  34:      int i;
  35:      printf(prompt);
  36:      for(i=0;i<size;i++)
  37:          printf("\t%d",p[i]);
  38:  
  39:      printf("\n");
  40:  }

 

Important to note is memory leak may not cause a severe damage to you program as in case of wild pointers or dangling pointers as long as you don’t run out of memory. The worst outcome will be out of memory. Still for a larger system this is un-welcome.

For along running system it could result in performance loss of program crashing due to lack of available memory.

 

Summary

Working with pointer in unmanaged environment requires a lot of concerns from programmers. Of course the foremost is we should we aware what pointer is pointing to and it shouldn’t be wild. Bigger challenges come when we deal with dynamic memory. When we allocate memory; it is our responsibility to free it. However, the problem is, weather we free it or not we can land in trouble. Not freeing what we should causes memory leak and freeing what we shouldn’t causes dangling pointers…

 

Unmanaged Pointer vows…

· Un-initialised pointers or Wild Pointers can manipulate data in unwanted and unexpected ways.

· Not freeing a memory after its use is over causes Memory Leak which can cause performance problem; worst program going out of memory.

· Freeing a memory in unwanted manner causes Dangling Pointers which can result in cross-linked memory and unpredictable behaviour.

 

 

One Reply to “Pointers – Vows and Concerns”

Leave a Reply

Your email address will not be published. Required fields are marked *