Docstoc

Dynamic Memory Allocation

Document Sample
Dynamic Memory Allocation Powered By Docstoc
					Dynamic Memory Allocation
      When we declare an array, we need to reserve some memory to
store the elements of this array. This memory allocation and it is static.
That is when we declare an array, we specify the number of elements in
that array and a fixed memory is allocated. Once declared the size of
the array cannot be changed.
      But there are situations in which we may want to declare the
variable and not allocate memory for it until we use that variable. We
may also want to free the memory allocated for a variable after its use is
over. These are some of the things we will concentrate on in this
lecture.
      The dynamic allocation of memory during the program execution
is achieved through two built in functions malloc or calloc, realloc and
free. There is also sizeof() function used to determine the number of
bytes occupied by an entity in memory. Let is look at the use of these
functions through a couple of examples.


Dynamic_memory.c
#include<math.h>
#include<stdio.h>
#define l 4
main()
{
       int *a, i,*p;
      float *b,*c;
      a=(int*) malloc(l);
      for (i=0; i<l; i++)
      {
             *(a+i)=i;
      }
      for (i=0; i<l; i++)
      {
              printf ("a %d %d %u \n",i,*(a+i),(a+i));
      }
       p=(int*) calloc(l,4);
       for (i=0; i<l; i++)
      {
             *(p+i)=i*2;
      }
      for (i=0; i<l; i++)
      {
             printf(" p %d %d %u %d\n",i,*(p+i),(p+i),sizeof(p));
      }
      b=(float*)malloc(l);
       for(i=0;i<l+2;i++)
      {
             *(b+i)=i*4.0;
      }
      for(i=0;i<l+2;i++)
      {
              printf(" b %d %f %u %d\n", i,*(b+i),(b+i),sizeof(b));
      }
       c= calloc(l,8);
       for(i=0;i<l;i++)
      {
             *(c+i)=i*4.0;
      }
       for(i=0;i<l+1;i++)
       {
              printf(" c %d %f %u %d \n", i,*(c+i),(c+i),sizeof(c));
       }
      for(i=l+1;i<l+2;i++)
       {
       printf(" b %d %f %u \n", i,*(b+i),(b+i));
       }
}

      In the program above we create an integer pointer *a and two
floating point pointers *b,*c. Now we want to store a string of numbers
using these pointers, instead of using a fixed size array.
      To achieve this we fist have to allocate enough space in the
memory to which the pointers point to. We will allocate just enough
memory to store the elements we want to . For example in the above
program we want to store 4 integer values.         By using the malloc
function we will allocate memory for an integer array of size 4. Note the
usage of malloc () here.      We invoke it by the statement a=(int*)
malloc(l); We could also do the same with p=(int*) malloc(l*sizeof(int));
or p=(int*) malloc(l*size(a)); where l=4. One important thing to note
here is that since malloc returns a void pointer, we need to type cast it
before equating it to the pointer we want. In the case above a is an
integer so we have to use (int *) before malloc. Similarly we see the use
of a malloc to allocate memory for a float pointer b . We use the pointer
p to demonstrate that we can do exactly the same using the function
calloc. The function is exactly the same , except that we need not type
cast it now and also that we have to give a second argument to
calloc,which is the number of bytes need to store one variable. In most
of the modern compiler this value is ignored by the function.
      So far we have seen operations which is pretty much like that in
the fixed size arrays. The only difference is that we assign the memory
only just before the variable is used. This by itself is not very useful
unless we can change this memory allocation , that is increase it if we
want more and remove it if we don't want to use the variable again in
the program. This is what realloc and free will do for us. Let us look at
that with an example.
      realloc.c
      /*   Dynamic memory allocation realloc and free */
           #include<math.h>
           #include<stdio.h>
           #define l 5
           main()
           {
           float *a;
           int i;

           a=(float*) malloc(l);
           for(i=0;i<l;i++)
              { *(a+i)=i*3.0;}
           for(i=0;i<l;i++)
           {
            printf("a %d %f %u \n",
                   i,*(a+i),(a+i));
           }
           a=(float*)realloc(a,sizeof(float)*(l+3));
           for(i=0;i<l+3;i++)
              { *(a+i)=i*3.0;}
           for(i=0;i<l+3;i++)
           {
            printf("a %d %f %u \n",
                   i,*(a+i),(a+i));
           }

           free(a);
           }

In the above program we have a pointer a which is of type float . We
then give it enough momory space to store 5 elements. After filling and
printing out the address of those locations and the value stored in them
we increase the"size" of the memory allocated by the statement
"a=(float*)realloc(a,sizeof(float)*(l+3));". This statement will increase the
memory space to store 3 more floating points. You can see by yourself
that if you remove this line and try to store more than5 elements into a
you will get segmentation fault. The last statement in the program
"free(a);" free all the space allotted to a .
Thus by using malloc, realloc and free we can change the memory
taken up by the program as required by it. This is particularly useful
when we have to use large temporary arrays in a calculation.
Functions and pointers to functions.
       We saw how to pass array to a function, return array from a
function, and declare arrays, pointer arrays, pointers to arrays and also
dynamic memory allocation. We will no see a different use of pointers,
that is to invoke function calls. Before we go on to the the description of
pointer to a function, lets have quick review of the structure of functions


All functions have the following components.

    Definition

      type function name (arguments passed to the function)
      variable declaration of the arguments
   { local variable declarations;
        statements;}


    Argument passing
   Two ways of passing variables to a function are
       (1) call by value
               Here the function work with a copy of the variable. Changes
   made in the function will not effect its value in the calling function
       (2) call by reference
               Here the address of the variable is passed to the function.
   Changes made in the function will change its value in the calling
   function.
   Let us look at an example to remind ourself about these differences.
      Example (variable-passing.c)
#include<math.h>
#include<stdio.h>
#define l 4
main()
{
      float b; int a[2],*c;
      void myfunction();
      c=(int*)malloc(1);
      b=10.0;
      *c=5;
       a[0]=1;a[1]=2;
       printf ("before function      call  %f %d       %d %d\n",
b,a[1],a[2],*c);
      myfunction (b,a,c);
      printf ("after function call %f %d %d %d\n", b,a[1],a[2],*c);
 }

void myfunction (x,y,d)
 float x;
 int y[2],*d;
{
       float z;
       x=2*x;
       y[0]=3*y[0];
       y[1]=3*y[1];
       *d=*d+2;
 }


In this example the main function is passing "b,a and c" to "myfunction",
which receives it as "x,y and d ". Since a is and array and c is a
pointer they are passed by "reference" while b is passed by value.
Inside myfunction all the values are altered. We will printout the values
of "b,a and c" in the main function before and after the call to
myfunction. This is what we get,
before function call 10.000000 1 2 5
after   function call 10.000000 3 6 7


We see that the variable that is passed by value does not get altered
while any changes made to quantities, that are passed by reference, in
the sub function will alter its value in the main function as well.


Pointers to Functions
On may occasions we may want to write a program to which a user
defined function can be passed. For example , as you will see later in
this course, one can write a general program to solve an ordinary
differential equation. We would then like to have it in such a way that a
user can write a function, which evaluate all the derivatives of the
particular problem, and pass it to the ODE solver. We will now see how
this can be achieved by using a pointer.


Function name can be used as a pointer to point to functions like the
name of the array is a pointer to its base address. We can also define a
pointer, point it to a function and then use that pointer to invoke the
function. The pointer to a function should be of the same "type" as the
function.
If we have to pass a function pointer to another function, we have to
define them as "external". That is they are "global" to the program and is
defined outside any function boundaries. Lets look at an example for

this now.
/*Pointer to a function and passing the pointer to a function */
  passing-function.c
/*   Pointer to a function and passing the pointer to a function */
     #include<math.h>
     #include<stdio.h>
     #define l 4
    float cube(float);
     main()
     {
     float b;
     void (*func_ptr)();
     void myfunction();
     b=2.0;
     func_ptr=myfunction;
     (*func_ptr)(b,&cube);
     }


        void myfunction (x,powerthree)
         float x;
         float (*powerthree)(float);
       {
          float z;
          x=2*x;
          z=(*powerthree)(x);
           printf("%f\n", z);
}

    float cube(x)
     float x;
    {
      float z;
      z=x*x*x;
      return z;
    }
Here cube is an external function and is defined outside of the function
boundaries. This function calculates the 3rd power of any floating point
variable passed to it and returns it as a floating point. Thus this function
is of the type "float".
In the main function we have defined a pointer func_ptr. Since we want
to use it to a function which is of the type "void" we need to define this
pointer also as "void".
The function myfunction has a floating point and a function pointer as
its arguments. Instead of invoking this function directly, we use func_ptr
for it. Note that we are passing the address of the external function,
cube, as an argument here. myfunction receives it as a floating point x
and function powerthree.       When powerthree is called inside this
function, it is actually invoking the function cube, which is supplied as
external.
We thus see the use of function pointer and also the way to pass a
function to another function here. We will make use of them later in the
coarse while solving ordinary differential equations.