Search This Blog

Showing posts with label variables. Show all posts
Showing posts with label variables. Show all posts

Dynamic Memory Allocation in C - Explanation With Examples

In static memory allocation, we know how much memory (bytes) is going to be used before execution of the program. Dynamic memory allocation is essential where the amount of memory the needed by the program depends on the input of the user or any other input obtained during execution time. That is why it is called dynamic memory allocation.

Consider an example of students progress report (for the sake of simplicity). The number of students are different in different classes. There fore, we have to read the number of students from the user (data entry operator). For each student, we need an integer for register number, a few integers to store scores in subjects, a few characters to store address and so on. In this case, the total amount of memory needed depends on the number of students in a class. There fore, the amount of memory that should be allocated for the program should be decided based on the input. In such cases we use dynamic memory allocation.

C programming language allows dynamic memory allocation. Most of modern programming languages use dynamic memory allocation. Java is an example. Unlike C, there is not a concept of pointers in Java because all variables are actually pointers.

Functions for Dynamic Memory Allocation in C

The functions used for dynamic memory allocation or deallocation are malloc, realloc, calloc and free. These functions are defined in the header file stdlib.h
malloc
This function is used to allocated specified number of bytes.
realloc
Used to increase or decrease size of a block of memory. Allocation or Deallocation of bytes is performed if necessary.
calloc
Allocates specified number of bytes and also intialises all bytes to zero. This function allows to specify how many blocks of specified size should be allocated.
free
Deallocates and releases the specified block of memory.
We shall see each function with examples.

Malloc function

First, we will see the syntax of malloc function. Then it will be easier to explain. Syntax is as follows:

void * malloc(int sizeInBytes);

The above shown prototype of malloc function tells that it always return a pointer to 'void' data type. That is, the pointer can be type-casted to int pointer, char pointer or to any other data type. malloc functions takes a parameter which is the amount of memory (number of bytes) to be allocated. It is recommended to specify the size using sizeof operator. We will see a few examples of dynamic memory allocation using malloc function.

int *p=malloc(10*sizeof(char));
Allocates memory to accommodate 10 characters.
int *p=malloc(20*sizeof(int));
Allocates memory to accommodate 20 integers.
int *p=malloc(sizeof(float));
Allocates memory to accommodate a float.
int *p=malloc(10*sizeof(struct student));
Allocates memory to accommodate 10 instances of structure named student. This is how to store derived datatypes (user defined data types) like structures dynamically in c.

Realloc Function

Realloc function is used either to shrink or to expand an already allocated memory. It is called after allocation of memory using malloc or calloc function. Suppose we initially allocated memory for 10000 characters dynamically. Later, during the of execution of program, we find that only 5000 characters need to be stored. Therefore, we are not going to use the rest. To avoid memory wastage, we may deallocate the remaining 5000 character spaces trailing being the used 5000. The following code will shrink the initially allocated 10000 chars to 5000 chars by deallocating the remaining.

void * realloc(void *pointer,size_t size)

The first parameter pointer is the pointer to the memory block allocated earlier. The next argument size is the new (updated) size. It size is greater than the older size, additional memory will be allocated to get size number of bytes allocated in total. If it is less than older size, a part of memory will be deallocated which is equal to the difference between initial size and new size. If first parameter is NULL, a fresh block with specified size will be allocated.

char *ptr;
//Initial allocation
ptr = (char *) malloc(150);

//Reallocating memory to 50 char
ptr = (char *) realloc(ptr, 50);

Calloc Function

Calloc function is not much significantly different from malloc. The differences between malloc and calloc are:

  • Calloc lets you to specify the number of variables (of same data type) and space needed by each data type by taking two parameters.
  • When allocated using malloc, the memory block may contain junk data (garbage values) but calloc initializes every allocated byte to zero.
The following code fragment shows example use of calloc with structure:

#include<stdlib.h>
struct student
{
int rollno;
char name[30];
};

int main()
{
struct student *list,*temp;
list=(struct student *)calloc(5,sizeof(struct student));
for(temp=list;temp-list<5;temp++)
    {
    printf("Enter roll number and name of student\n");
    scanf("%d%s",&temp->rollno,&temp->name);
    }
printf("\nThe students are:\n");
for(temp=list;temp-list<5;temp++)
    {
    printf("Roll number: %d  Name: %s\n",temp->rollno,temp->name);
    }
free(list);
return 0;
}
Output
Enter roll number and name of student
1
matthew
Enter roll number and name of student
2
mathews
Enter roll number and name of student
3
shareef
Enter roll number and name of student
4
muneer
Enter roll number and name of student
5
nihal

The students are:
Roll number: 1  Name: matthew
Roll number: 2  Name: mathews
Roll number: 3  Name: shareef
Roll number: 4  Name: muneer
Roll number: 5  Name: nihal

In the above example a structure named student is used. Each structure variable has a roll number and name. Memory to store for 5 student structure variables are allocated using calloc. The pointer arithmetic for pointers to structures is also demonstrated in above program.

Free Function

The free function is used to free (deallocate) an already allocated block of memory. When your program no longer needs the dynamically allocated block of memory, the free function should be called to return the memory occupied to the free store. In the above example program, the following line of code deallocated the allocated block of memory.

free(list);

The free function takes the pointer to the block of memory which is allocated dynamically as parameter and frees or deallocates the block so that it can be used later.

Storage Classes for Variables in C Programming Language

Every variable in C programming language has two properties; type and storage class. 'Type' refers to the data type of the variable such as integer, character, floating point values etc. It also deals with the size of the variable ( in bytes). 'Storage class' determines the part of memory where storage is allocated for the variable and how long the storage allocation continues to exist. It also determines the scope which specifies the part of the program over which a variable name is visible, i.e. the variable is accessible by name. The scope restriction can be overrode by making use of pointers. Whatever, in short, storage class is the property that determines the part of memory where storage is allocated, the lifetime of variable and the scope of the variable.

There are for storage classes in C programming:

  • Automatic
  • Register
  • External
  • Static



Automatic variables:

'Aromatic' or 'auto' is the storage class which is default for all local variables, i.e. variables declared inside a function or a block is automatic by default. They are normally declared s at the start of the block. Memory is allocated automatically upon entry to a block and freed automatically upon exit from the block. The scope of automatic variables is local to the block in which they are declared, including any blocks nested within the block. For these reasons, automatic variables are often referred to as 'local variables'. Since any variable declared inside a block or a function is 'local' by default, the keyword 'auto' which is used to declare automatic variables, are rarely used.

int fact(int n)
{
auto int result; /* automatic variable declaration*/
if(n==0)
result =1;
else
result =n*fact (n-1);
return (result);
}



In above example, an automatic integer variable 'result' is declared within the function 'fact'. The variable is local to the function as it's declared as automatic. But, it is not necessary to use the keyword 'auto' because even if auto is avoided, the variable will be auto by default.

Register Variables:

A Register variable is a special case of automatic variable. Register variables are identical to automatic variables in the case of scope, i.e, they are local to the function or block in which they are declared. The only difference is in the part of memory in which the storage is allocated. An automatic variable is always stored in RAM whereas, as the name indicates, register variables are stored in registers. When we consider a program in which a certain variable is frequently used, the performance of the program can be improved if it is stored in a register instead of RAM since registers are very much faster memory components than RAM. Variables used in enormously repeated loops of large programs, variables used as parameters for frequently called functions etc. can be declared as register variables in order to increase the performance of the program considerably.

To declare a register variable, the keyword 'register' should be prefixed to the data type as shown:

register int a;

When the compiler encounters a register variable declaration, it tries to store the variable in microprocessor's register rather than RAM. Value stored in registers are much faster than those in RAM. Since the number of registers are limited, if it couldn't be stored in register it will store it in RAM. Even the availability of resisters doesn't guarantee faster execution of program. For example, if too many register variables are declared and there are not enough registers to store all of them, values in some of the registers would have to be moved to temporary storage in memory in order to clear those registers for other variables. Thus much time may be wasted in shipping the data in and out of the registers. In addition, careless use of register variables may interfere with other uses of registers by the compiler, such as storage of temporary values in expression evaluation. In short, the keyword 'register' should be used carefully and lavish usage may result in slower execution of program.

External variables:

In some applications it may be helpful to have data which is accessible from within any block and/or which remains in existence for the entire execution of program. Such variables are called global variables, and the C language provides storage classes which can meet these requirements; namely, the external storage class.
External variables may be declared outside any function block in a source code file the same way any other variable is declared; by specifying its type and name. No storage class specifier is used -- the position of the declaration within the file indicates external storage class. Memory fit such variables is allocated when the program begins execution, and remains allocated until the program terminates. For most C implementations, every byte of memory allocated for an external variable is initialised to zero. The scope of the external variable is global,i.e. the entire source code in the file following the declarations. All functions following the declaration may access the external variable by using its name. However, if a local variable having the same name is declared within a function, references to the name access the local variable cell.

#include<stdio.h>
int m=0; /* External variable */
main ()
{
int m=1; /* auto variable */
printf("m=%d",m);
}

The output of this code is:
m=1

Static variable

The difference between static and automatic storage class is that the lifetime of a static variable is more than that of the automatic variable. The difference between them is that static variable do not disappear when the function is no longer active. There value persist. If control comes back to the same function again , the static variables have the same values they had last time around. The difference can be easily understood by comparing two programs with same variable with different storage classes. Let us compare two programs and their outputs.






#include<stdio.h>

void findsum(int a)

   {

   auto int sum=0; /*automatic*/

   sum+=a;

   printf("\nsum=%d",sum);

   }

void main()

   {

   int p;

   for(p=1;p<4;p++)

     {

     findsum(p);

     }

   }
#include<stdio.h>

void findsum(int a)

   {

   static int sum=0; /*static*/

   sum+=a;

   printf("\nsum=%d",sum);

   }

void main()

   {

   int p;

   for(p=1;p<4;p++)

     {

     findsum(p);

     }

   }

Output:
sum=1
sum=2
sum=3
Output:
sum=1
sum=3
sum=6

In the first example, the variable sum in findsum() is declared as an automatic variable while it is static in second example. In first example, at the first call of function findsum() (when p=1), the variable sum in the function is initialized as with zero. After the completion of execution of the function findsum(), the life of variable sum ends. In the next call, again sum is allocated and initialised. So, each time the number is going to be added, the initial value of sum will be 0.

In second example, once the function gets executed, the variable sum is allocated and initialised with zero. Since it is declared as a static variable, the line static int sum=0; will not be executed in the next executions of the function. i.e. the declaration statement (along with initialisation if any) will not be executed each time the function is called. Moreover, if one execution of the function is over, the static variable will not be deallocated. If control comes back to the same function again , the static variables have the same values they had last time around. There for the variable sum will give cumulative values in second example.