Dynamic Memory Allocation

Why Dynamic Memory Allocation is Required ?

The exact size of array is unknown until the compile time,i.e., time when a compiler compiles code written in a programming language into a executable form. The size of array you have declared initially can be sometimes insufficient and sometimes more than required. Dynamic memory allocation allows a program to obtain more memory space, while running or to release space when no space is required.

Although, C language inherently does not has any technique to allocated memory dynamically, there are 4 library functions under "stdlib.h" for dynamic memory allocation.

malloc()

If the allocation succeeds, a void pointer to the allocated memory is returned or NULL is returned if there is insufficient memory available.To return a pointer to a type other than void, use a type cast on the return value.

If size is 0, malloc allocates a zero-length item in the heap and returns a valid pointer to that item. Always check the return from malloc, even if the amount of memory requested is small.

If it is unable to find the requested amount of memory, malloc() function returns NULL. So you should really check the result for errors:

Syntax : ptr=(cast-type*)malloc(byte-size)
eg.      ptr = (int *)malloc(100 * sizeof (int)); //The contents of allocated memory are not changed. i.e., the memory contains unpredictable or garbage values which creates a risk.
This statement will allocate either 200 or 400 according to size of int 2 or 4 bytes respectively and the pointer points to the address of first byte of memory.

#include <stdio.h>
int main()
{
        int *p;
        p = (int *) malloc(sizeof(int)*2147483647);
        if (p==NULL)
                printf("Out of memory\n");
        return 0;
}

Output :
Out of memory
calloc()

allocates a contiguous block of memory large enough to hold nelements of size bytes each. The allocated region is initialized to zero.

Initialization : malloc() does not initialize the memory allocated, while calloc() initializes the allocated memory to ZERO.

Syntax : ptr=(cast-type*)calloc(n,element-size);
This statement will allocate contiguous space in memory for an array of n elements

eg. int *ptr = calloc(10,sizeof (int)); // The allocated region is initialized to zero.
This statement allocates contiguous space in memory for an array of 25 elements each of size of float, i.e, 4 bytes.


calloc(m, n) is essentially equivalent to:
p = malloc(m * n);
memset(p, 0, m * n);
  // setting value to zero

Why does malloc() return a void*?
It’s because malloc() has no idea which type of object we want to put in that memory.


Some Hands On :

#include <stdio.h>
void allocateArray(int *arr){
        arr=(int*)malloc(100);
        arr[0]=137;
        printf("arr[0] in allocateArray :%d\n", arr[0]);
}

int main()
{
        int *arr;
        allocateArray(arr);
        printf("arr[0] in main :%d", arr[0]);
        getchar();
        return 0;
}


What will be output :

When calling allocateArray in main, you are passing array by value, so it is completely unchanged by the call to allocateArray . the “array” inside allocateArray is a copy of the original array from main(), and it is this copy that is assigned the result of the malloc call and  not the original array in main().

OUTPUT:
arr[0] in allocateArray :137
arr[0] in main :0

free()
Dynamically allocated memory with either calloc() or malloc() does not get return on its own. The programmer must use free() explicitly to release space.

syntax : free(ptr);
This statement cause the space in memory pointer by ptr to be deallocated.

realloc()
If the previously allocated memory is insufficient or more than sufficient. Then, you can change memory size previously allocated using realloc().

Syntaxptr=realloc(ptr, newsize);

Here, ptr is reallocated with size of newsize.
eg. ip = realloc(ip, sizeof(ip) + sizeof(int)*5);

Now we have some more space through adding the sizeof the complete array and an additional 5 spaces for ints... STOP! This is NOT how you use realloc. Again. The above example is wrong. Why?
  • First, sizeof(ip) does not give the size of the allocated space originally allocated by malloc (or a previous realloc). Using sizeof() on a pointer only returns the sizeof the pointer, which is probably not what you intended.
  • Also, what happens if the realloc on ip fails? ip gets set to NULL, and the previously allocated memory to ip now has no pointer to it. Now we have allocated memory just floating in the heap without a pointer. This is called a memory leak. This can happen from sloppy realloc's and not using free on malloc'd space.

So what is the correct way? Take this code for example:

  int *tmp;
  if ((tmp = realloc(ip, sizeof(int) * (INITIAL_ARRAY_SIZE + 5))) == NULL) {
    /* Possible free on ip? Depends on what you want */
    fprintf(stderr, "ERROR: realloc failed");
  }
  ip = tmp;

Now we are creating a temporary pointer to try a realloc. If it fails, then it isn't a big problem as we keep our ip pointer on the original memory space. Also, note that we specified the real size of our original array and now are adding 5 more ints (so 4bytes*(5+5) = 40bytes, on a typical 32-bit machine).

New memory allocation will be contiguous, explained in below program.


#include <stdio.h>
#include <stdlib.h>
int main()
{
        int *ptr,i,n1,n2;
        printf("Enter size of array: ");
        scanf("%d",&n1);
        ptr=(int*)malloc(n1*sizeof(int));
        printf("Address of previously allocated memory: ");
        for(i=0; i<n1; ++i)
                printf("%u\t",ptr+i);
        printf("\nEnter new size of array: ");
        scanf("%d",&n2);
        ptr=realloc(ptr,n2);
        printf("Address after realloc is :");
        for(i=0; i<n2; ++i)
                printf("%u\t",ptr+i);
        return 0;
}


OUTPUT :
Enter size of array: 1
Address of previously allocated memory: 134520840
Enter new size of array: 2
Address after realloc is :134520840     134520844


bzero()

bzero(3) fills the first n bytes of the pointer to zero. Prototype:
 void bzero(void *s, size_t n);

memset()
If you need to set the value to some other value (or just as a general alternative to bzero), you can use memset.

The C library function void *memset(void *str, int c, size_t n) copies the character c (an unsigned char) to the first n characters of the string pointed to, by the argument str. This function returns a pointer to the memory area str.

Following is the declaration for memset() function.

void *memset(void *str, int c, size_t n)
where you can specify c as the value to fill for n bytes of pointer s.

str -- This is a pointer to the block of memory to fill.

c -- This is the value to be set. The value is passed as an int, but the function fills the block of memory using the unsigned char conversion of this value.

n -- This is the number of bytes to be set to the value.

The following example shows the usage of memset() function.

#include <stdio.h>
#include <string.h>
int main ()
{
   char str[50];

   strcpy(str,"This is string.h library function");
   puts(str);

   memset(str,'$',7);
   puts(str);
   
   return(0);
}

Output :

This is string.h library function
$$$$$$$ string.h library function

No comments:

Post a Comment