Unit 13
Dynamic Memory Allocation
- How Memory Management in C works?
When you declare a variable using a basic data type, the C compiler automatically allocates memory space for the variable in a pool of memory called the stack.
For example, a float variable takes typically 4 bytes (according to the platform) when it is declared. We can verify this information using the sizeof operator as shown in below example
#include <stdio.h>
Int main() { float x; printf("The size of float is %d bytes", sizeof(x)); return 0;}
The output will be:
The size of float is 4 bytes
Also, an array with a specified size is allocated in contiguous blocks of memory, each block has the size for one element:
#include <stdio.h>
Int main() { float arr[10];
Printf("The size of the float array with 10 element is %d", sizeof(arr)); return 0;}
The result is:
The size of the float array with 10 element is 40
As learned so far, when declaring a basic data type or an array, the memory is automatically managed. However, there is a process for allocating memory which will permit you to implement a program in which the array size is undecided until you run your program (runtime). This process is called "Dynamic memory allocation."
2. What is Dynamic Memory Allocation?
Dynamic Memory Allocation is manual allocation and freeing of memory according to your programming needs. Dynamic memory is managed and served with pointers that point to the newly allocated memory space in an area which we call the heap.
Now you can create and destroy an array of elements dynamically at runtime without any problems. To sum up, the automatic memory management uses the stack, and the dynamic memory allocation uses the heap.
The <stdlib.h> library has functions responsible for dynamic memory management.
Function | Purpose |
Malloc | Allocates the memory of requested size and returns the pointer to the first byte of allocated space. |
Calloc | Allocates the space for elements of an array. Initializes the elements to zero and returns a pointer to the memory. |
Realloc | It is used to modify the size of previously allocated memory space. |
Free | Frees or empties the previously allocated memory space. |
3. What is The malloc Function explain with example?
The malloc() function stands for memory allocation. It is a function which is used to allocate a block of memory dynamically. It reserves memory space of specified size and returns the null pointer pointing to the memory location. The pointer returned is usually of type void. It means that we can assign malloc function to any pointer.
Syntax
Ptr = (cast_type *) malloc (byte_size);
Here,
- Ptr is a pointer of cast_type.
- The malloc function returns a pointer to the allocated memory of byte_size.
Example: ptr = (int *) malloc (50)
When this statement is successfully executed, a memory space of 50 bytes is reserved. The address of the first byte of reserved space is assigned to the pointer ptr of type int.
Consider another example:
#include <stdlib.h>
Int main(){
Int *ptr;
Ptr = malloc(15 * sizeof(*ptr)); /* a block of 15 integers */
if (ptr != NULL) {
*(ptr + 5) = 480; /* assign 480 to sixth integer */
printf("Value of the 6th integer is %d",*(ptr + 5));
}
}
Output:
Value of the 6th integer is 480
- Notice that sizeof(*ptr) was used instead of sizeof(int) in order to make the code more robust when *ptr declaration is typecasted to a different data type later.
- The allocation may fail if the memory is not sufficient. In this case, it returns a NULL pointer. So, you should include code to check for a NULL pointer.
- Keep in mind that the allocated memory is contiguous and it can be treated as an array. We can use pointer arithmetic to access the array elements rather than using brackets [ ]. We advise to use + to refer to array elements because using incrementation ++ or += changes the address stored by the pointer.
Malloc function can also be used with the character data type as well as complex data types such as structures.
4. What is The free Function?
The memory for variables is automatically deallocated at compile time. In dynamic memory allocation, you have to deallocate memory explicitly. If not done, you may encounter out of memory error.
The free() function is called to release/deallocate memory. By freeing memory in your program, you make more available for use later.
For example:
#include <stdio.h>
Int main() {
Int* ptr = malloc(10 * sizeof(*ptr));
If (ptr != NULL){
*(ptr + 2) = 50;
printf("Value of the 2nd integer is %d",*(ptr + 2));
}
Free(ptr);
}
Output
Value of the 2nd integer is 50
5. What is The calloc Function explain?
The calloc function stands for contiguous allocation. This function is used to allocate multiple blocks of memory. It is a dynamic memory allocation function which is used to allocate the memory to complex data structures such as arrays and structures.
Malloc function is used to allocate a single block of memory space while the calloc function is used to allocate multiple blocks of memory space. Each block allocated by the calloc function is of the same size.
Syntax:
Ptr = (cast_type *) calloc (n, size);
- The above statement is used to allocate n memory blocks of the same size.
- After the memory space is allocated, then all the bytes are initialized to zero.
- The pointer which is currently at the first byte of the allocated memory space is returned.
Whenever there is an error allocating memory space such as the shortage of memory, then a null pointer is returned.
The program below calculates the sum of an arithmetic sequence.
#include <stdio.h>
int main() {
int i, * ptr, sum = 0;
ptr = calloc(10, sizeof(int));
if (ptr == NULL) {
printf("Error! memory not allocated.");
exit(0);
}
printf("Building and calculating the sequence sum of the first 10 terms \ n ");
for (i = 0; i < 10; ++i) { * (ptr + i) = i;
sum += * (ptr + i);
}
printf("Sum = %d", sum);
free(ptr);
return 0;
}
Result:
Building and calculating the sequence sum of the first 10 terms
Sum = 45
6. What is The realloc Function?
Using the realloc() function, you can add more memory size to already allocated memory. It expands the current block while leaving the original content as it is. Realloc stands for reallocation of memory.
Realloc can also be used to reduce the size of the previously allocated memory.
Syntax
Ptr = realloc (ptr,newsize);
The above statement allocates a new memory space with a specified size in the variable newsize. After executing the function, the pointer will be returned to the first byte of the memory block. The new size can be larger or smaller than the previous memory. We cannot be sure that if the newly allocated block will point to the same location as that of the previous memory block. This function will copy all the previous data in the new region. It makes sure that data will remain safe.
For example:
#include <stdio.h>
Int main () {
char *ptr;
ptr = (char *) malloc(10);
strcpy(ptr, "Programming");
printf(" %s, Address = %u\n", ptr, ptr);
ptr = (char *) realloc(ptr, 20); //ptr is reallocated with new size
strcat(ptr, " In 'C'");
printf(" %s, Address = %u\n", ptr, ptr);
free(ptr);
return 0;
}
Whenever the realloc results in an unsuccessful operation, it returns a null pointer, and the previous data is also freed.
7. What is the Dynamic Arrays?
A Dynamic array allows the number of elements to grow as needed. They are widely used in Computer science algorithms.
In the following program, we create and resize an array dynamically
#include <stdio.h>
int main() {
int * arr_dynamic = NULL;
int elements = 2, i;
arr_dynamic = calloc(elements, sizeof(int)); //Array with 2 integer blocks
for (i = 0; i < elements; i++) arr_dynamic[i] = i;
for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]);
elements = 4;
arr_dynamic = realloc(arr_dynamic, elements * sizeof(int)); //reallocate 4 elements
printf("After realloc\n");
for (i = 2; i < elements; i++) arr_dynamic[i] = i;
for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]);
free(arr_dynamic);
}
Result at the screen:
Arr_dynamic[0]=0
Arr_dynamic[1]=1
After realloc
Arr_dynamic[0]=0
Arr_dynamic[1]=1
Arr_dynamic[2]=2
Arr_dynamic[3]=3
8. Explain Memory allocation of Recursive method
Each recursive call creates a new copy of that method in the memory. Once some data is returned by the method, the copy is removed from the memory. Since all the variables and other stuff declared inside function get stored in the stack, therefore a separate stack is maintained at each recursive call. Once the value is returned from the corresponding function, the stack gets destroyed. Recursion involves so much complexity in resolving and tracking the values at each recursive call. Therefore we need to maintain the stack and track the values of the variables defined in the stack.
Let us consider the following example to understand the memory allocation of the recursive functions.
- Int display (int n)
- {
- If(n == 0)
- Return 0; // terminating condition
- Else
- {
- Printf("%d",n);
- Return display(n-1); // recursive call
- }
- }
Explanation
Let us examine this recursive function for n = 4. First, all the stacks are maintained which prints the corresponding value of n until n becomes 0, Once the termination condition is reached, the stacks get destroyed one by one by returning 0 to its calling stack. Consider the following image for more information regarding the stack trace for the recursive functions.
9. Explain mathematical function with examples
C Math
C Programming allows us to perform mathematical operations through the functions defined in <math.h> header file. The <math.h> header file contains various methods for performing mathematical operations such as sqrt(), pow(), ceil(), floor() etc.
C Math Functions
There are various methods in math.h header file. The commonly used functions of math.h header file are given below.
No. | Function | Description |
1) | Ceil(number) | Rounds up the given number. It returns the integer value which is greater than or equal to given number. |
2) | Floor(number) | Rounds down the given number. It returns the integer value which is less than or equal to given number. |
3) | Sqrt(number) | Returns the square root of given number. |
4) | Pow(base, exponent) | Returns the power of given number. |
5) | Abs(number) | Returns the absolute value of given number. |
C Math Example
Let's see a simple example of math functions found in math.h header file.
- #include<stdio.h>
- #include <math.h>
- Int main(){
- Printf("\n%f",ceil(3.6));
- Printf("\n%f",ceil(3.3));
- Printf("\n%f",floor(3.6));
- Printf("\n%f",floor(3.2));
- Printf("\n%f",sqrt(16));
- Printf("\n%f",sqrt(7));
- Printf("\n%f",pow(2,4));
- Printf("\n%f",pow(3,3));
- Printf("\n%d",abs(-12));
- Return 0;
- }
Output:
4.000000
4.000000
3.000000
3.000000
4.000000
2.645751
16.000000
27.000000
12
10. Explain string function with examples
C String Functions
There are many important string functions defined in "string.h" library.
No. | Function | Description |
1) | Strlen(string_name) | Returns the length of string name. |
2) | Strcpy(destination, source) | Copies the contents of source string to destination string. |
3) | Strcat(first_string second_string) | Concats or joins first string with second string. The result of the string is stored in first string. |
4) | Strcmp(first_string, second_string) | Compares the first string with second string. If both strings are same, it returns 0. |
5) | Strrev(string) | Returns reverse string. |
6) | Strlwr(string) | Returns string characters in lowercase. |
7) | Strupr(string) | Returns string characters in uppercase. |