![]() |
Image Source: https://www.pexels.com/photo/person-encoding-in-laptop-574071/ |
Introduction
In the ever-evolving world of software development, it has become crucial to create applications that not only run smoothly but also use memory wisely, especially for applications like embedded systems, where resources are limited. As data gets larger and software systems get more complex, how efficiently we handle memory can significantly impact how fast and responsive an application is. In this blog post, we will discuss some specific programming techniques for memory optimisation using C language.
Use const keyword
The const keyword is used to declare variables that do not change during program runtime. The variables that we declare with const keyword are often stored in ROM and therefore we can save RAM space. When RAM is limited, we can store variables to do not change their value throughout the program execution in ROM. This also ensures that these values do not get modified by mistake during the program execution.
Example using const keyword:
const int a = 5;
Create arrays using dynamic memory allocation(DMA).
Static or fixed-size arrays get stored in data segment if they are global or stack segment if they are defined within a function. The memory assigned to them cannot be deallocated.
Instead, use DMA to create arrays. When we do this the memory assigned to the array must be deallocated after use. Dynamically created arrays get stores in the heap segment of memory.
Example for creating an array using DMA:
#include<stdio.h>
//stdlib.h header file is required to be able to use DMA functions
#include<stdlib.h>
int main(){
//Allocate memory for array.
int *arr = (int*)malloc(5*sizeof(int));
//Getting array elements as user input
for (int i=0;i<5;i++){
scanf("%d",&*(arr+i));
}
//Printing elements of array
for (int i=0;i<5;i++){
printf("%d\n",*(arr+i));
}
//Deallocating memory assigned to array.
free(arr);
}
Create string arrays using
When declaring string arrays use,
char *arr[12] = {"Doraemon", "Shin Chan", "Naruto", "Dragonball"};
instead of
char arr[][12] = {"Doraemon", "Shin Chan", "Naruto", "Dragonball"};
For more details refer to my blog post on string arrays: https://siliconcat.blogspot.com/2023/08/array-of-strings-in-c.html
Use pass by reference instead of pass by value
When passing large data structures as function arguments, use the pass by reference method. This is because when we pass by value a copy of the argument is made and passed to the function. Pass by reference does not make a copy of the variables and modifies the original argument by using it's address. An example that uses pass by reference is shown below:
#include <stdio.h>
// Define a simple struct representing a person
struct Person {
char name[50];
int age;
};
// Function to modify the age of a person using pass by reference
void modifyAge(struct Person *personPtr, int newAge) {
personPtr->age = newAge;
}
int main() {
// Create a person instance
struct Person person;
strcpy(person.name, "Alice");
person.age = 25;
// Print the original age
printf("Original age: %d\n", person.age);
// Pass the person instance by reference and modify age
modifyAge(&person, 30);
// Print the modified age
printf("Modified age: %d\n", person.age);
return 0;
}
Declare members in a structure in order of decreasing size
When creating a structure, declare the variable occupying more memory space first. This is because of memory alignment. The members of a structure are stored in memory locations that are like an array. If the storage allotted to the variables are not aligned, then extra memory will be allocated for alignment(padding). To avoid the memory wastage declare the variables in order of decreasing size to keep the padding at minimum.
Example: Do not create a structure like this,
struct Example {
char a; // 1 byte
float b; // 4 bytes (requires 3 bytes of padding to align to 4-byte boundary)
char c; // 1 byte
};
This is a better practice,
struct Example {
float b;
char a,c;
};
Use bitfields
When we know the size of the structure members we need beforehand, use bitfields to optimise memory. For example,
struct bitfields{
int a : 5; // 5 bits
int b : 10; // 10 bits
};
The memory allocated for the above structure is 4 bytes(32 bits). This is because we are specifying that we need a total of 15 bits of memory for our members, so they can be accommodated in 32 bits.
If we do not use bitfields , 8 bytes will be allocated for 2 integer type variables.
struct s1{
int a;
int b;
};
Conclusion
Those were just some of the coding practices that can help us make effective use of memory resources. Hope it was helpful.
Comments
Post a Comment