fixed size memory allocator interface without fragmentation on freeing the memory I was trying to write a memory pool interface which:

Grants memory of fixed size chunks in linked list style fashion.

On returning the memory there is no risk of memory fragmentation.
//mem_struct.h
#ifndef MEM_STRUCT_H
#define MEM_STRUCT_H

struct mem_struct
{
   char arr[4];
   struct mem_struct *next;
};

#endif



Now using above structure the interface will grant memory to the user (the function which demands memory):
//mem_allocator.c
#include&lt;stdlib.h&gt;
#include&lt;string.h&gt;
#include&quot;mem_struct.h&quot;
#define total 10     //max no. of fixed size memory blocks initialized at once in a pool

unsigned int total_pool_size=0;   //total bytes of memory in pool available
struct mem_struct *head=NULL;     //first node of memory pool

/* function to initialize memory pool of max total no. of memory blocks or less if memory not 
   available and add newly allocated blocks to existing memory pool blocks */
int mem_pool_init()
{
   struct mem_struct *temp;
   unsigned short count = 0; //no. of memory blocks/chunks successfully allocated and added to existing memory pool

   while(count &lt; total)
   {
      temp = calloc(1,sizeof(*temp));
      if(temp)
      {
         temp-&gt;next = head;
         head = temp;
         total_pool_size += sizeof(temp-&gt;arr);
         count++;
      }
      else
         return 1;
   }
   return 0;
}


//function which grants memory in bytes to the user request 
void* mem_grant(unsigned int siz)   
{
    struct mem_struct *temp_head = NULL;  //pointer to first block of memory to be returned to the requesting function
    if(siz &gt; 0)
    {
       //This loop will go on till there is sufficient memory in the memory pool to allocate memory of size - siz or the CPU is left with no memory 
       while(total_pool_size &lt; siz)
           if(mem_pool_init())
              return NULL;

       struct mem_struct *temp = head;
       unsigned int total_nodes = 0;   //total no of nodes of memory to be returned to the requesting function

       if(total_pool_size &gt;= siz)
       {
          temp_head = head;

          if(siz%sizeof(temp_head-&gt;arr) &gt; 0) //to determine no. of memory blocks to be returned to the user request
             total_nodes = siz/sizeof(temp_head-&gt;arr) + 1;
          else
             total_nodes = siz/sizeof(temp_head-&gt;arr);

          while(total_nodes)
          {
              temp = temp-&gt;next;  
              --total_nodes;
              total_pool_size = total_pool_size - sizeof(temp-&gt;arr);
          }
          head = temp-&gt;next;
          temp-&gt;next = NULL;
       }
   }
   return (void *)temp_head;
}


//function to add the memory earlier allocated back to the memory block
void free_mem(void *temp_head) //temp_head points to the first byte of the memory allocated to the user using mem_grant
{
    if(temp_head)
    {
        struct mem_struct *temp = *temp_head;
    
        while(temp)
        {
           memset(temp,0,sizeof(temp-&gt;arr));

           if(!temp-&gt;next)
           {
               temp-&gt;next = head;
               break;
           }
           total_pool_size += sizeof(temp-&gt;arr);
        }
        head = temp_head;
    }
}

Here is the main function:
//main.c
#include&lt;stdio.h&gt;

extern void* mem_grant(unsigned int);
extern void  free_mem(void*);
extern unsigned int total_pool_size;

int main()
{
    void* ptr = mem_grant(42);
    if(ptr)
        printf(&quot;total_pool_size after grant %u\n&quot;, total_pool_size);
    free_mem(ptr);
    printf(&quot;total_pool_size after free %u\n&quot;, total_pool_size);
    return 0;
}

I am new to this part of programming and I want to know how can I improve as I don't have any reference material to lookup. Could someone please review this and tell me how this design is?
Thoughts as I read through your post:


  On returning the memory there is no risk of memory fragmentation


I'm not sure what you mean.  Do you mean that all the memory will be free i.e. not leaked?  I don't see anything related to memory fragmentation.



char arr[4];


I don't know your use case, but 4 bytes is very small for a modern computer.  You could easily spend 100 times longer dereferencing a pointer than reading 4 bytes.  Are you sure a linked list is the right choice here?



struct mem_struct *head=NULL;


If someone else makes a global variable named head in another .c file, then you will get a linker error because of duplicate symbols.  If you have to use a global variable, you should name it something distinctive like

struct mem_struct *global_mem_struct_head=NULL;


But a better idea is not to use a global variable at all, and pass a mem_struct* argument to each function.



//max no. of fixed size memory blocks initialized at once in a pool
#define total 10


How about this:

static const int max_init_memory_blocks = 10;


Now you effectively get the comment every time you use the variable, you get type checking, and even though this is a global, it's invisible outside of this translation unit/this file.

That said, you've done a good job adding comments throughout your code.



int mem_pool_init()


This function does initialization a fixed number of times.  Can you use a for loop?



calloc


If calloc succeeds and then fails, you'll leak the first allocations.



void* mem_grant


Why does this return void*?!  How is the user supposed to know they can only use the first few bytes?!



   while(total_pool_size &lt; siz)   //insufficient memory in pool
       if(mem_pool_init())
          return NULL;


Isn't this an infinite loop?



I'm going to stop here.  I think you would find a lot of these mistakes with some very simple test cases.  Then you can post an improved version.