Implement a Circular Buffer in C

Circular Buffer is also known as ring buffer. It works on the principle of FIFO (First in First Out). In circular buffer there are pointers which are used by the system to put in the data and remove the data. They are usually used in the data driven system. The following post will help you to learn circular buffer in C language.

Buffer Structure :

Any circular buffer contain at least two pointers. Head and Tail. We also initialize one buffer pointer which stores the address of the buffer which we will initialized. We also need to have a specific length which specifies number of data we can input in the buffer.

typedef struct{

  int8_t *buffer;
  int16_t head;
  int16_t tail;
  int16_t length;
  volatile bool full_status;

}circbuff;

Here we created a structure which has a pointer to our buffer, a head which contains the address of the buffer where we are going to push the new character. A tail which contain address of the data in the buffer which is going to be popped out first. Length which contains the total length of the buffer. Full Status can be used to check whether the buffer is full or not. 

Buffer Initialization : 

Steps required for Buffer Initialization.

  • Dynamically allocate memory.
  • Take the length from the user and update it into our structure.
  • Initialize head, tail, and buffer_full_status. 
  • Return the starting address of the buffer.
    circbuff * circbuff_init (int16_t length)
    {
      my_circ_buff = (circbuff *) malloc(sizeof(circbuff));
      my_circ_buff->buffer = (int8_t *)malloc (length);
      if(my_circ_buff->buffer=='NULL')
      {
        myprintf("Initialization failed\r\n");
    //		return
      }
      my_circ_buff->length = length;
      circbuff_reset(my_circ_buff);
    
      return (my_circ_buff);
    }

    Push data into Buffer :

    Steps required to enter data into buffer.

  • Check Buffer Status Full or Empty.
  • Take data and and push into the the buffer by accessing it using pointer.
  • Increment head pointer and data count in the buffer.
    void push(circbuff *circ_b, int8_t data_byte)
    {
      if (buffer_status(circ_b))
      {
        myprintf("Buffer is Full\r\n");
      }
      else
      {
      printf("Buffer is not full and Element can be inserted\r\n");
      }
    
      if (count != input_size)
      {
        circ_b->buffer[circ_b->head] = data_byte;
              printf ("Value inserted at position %d is %d\r\n", circ_b->head, circ_b->buffer[circ_b->head]);
        circ_b->head = (circ_b->head + 1) % input_size;
        count = (count % input_size) + 1;		//Denotes the number of elements in the Buffer
      }
    }
    

    Remove data from the buffer : 

    Steps required to remove data from the buffer :

  • Check Buffer status whether it is full or empty.
  • Use tail pointer and read the data from the buffer.
  • Increment tail pointer and decrement count.
    int8_t pop(circbuff *circ_b)
    {
      if (!buffer_status(circ_b))
      {
      printf("Buffer is Empty\r\n");
      }
      else
      {
        printf("Buffer contains elements and can be read\r\n");
      }
    
      if (count != 0)
      {
        printf ("Value read at position %d is %d\r\n", circ_b->tail, circ_b->buffer[circ_b->tail]);
        pop_value = circ_b->buffer[circ_b->tail];
        circ_b->tail = (circ_b->tail + 1) % input_size;
        count--;
        return (pop_value);
      }
      return -1;
    }

    Function to reset circular buffer : 

    void circbuff_reset(circbuff *circ_b)
    {
      circ_b->head = 0;
      circ_b->tail =0;
      circ_b->full_status =  false;
    }

    Function to check Buffer status : 

    Basically we use count variable to check whether the buffer is full or empty. 
    bool buffer_status(circbuff *circ_b)
    {
      if (count == 0)
      {
        circ_b->full_status = false;
      }
    
      else if (count == input_size)
      {
        circ_b->full_status = true;
      }
    
      return (circ_b->full_status);
    }
    

    Resize Buffer :

    Steps to resize buffer at any time :

  • Simply make a function to reallocate the buffer.
  • Check all the conditions. For ex. Buffer size cannot be zero. 
  • Use realloc which is inbuilt library in C. 
    my_circ_buff->buffer=(int8_t*)realloc(my_circ_buff->buffer, input_size);

     

Summary :

A circular buffer can be initialized by dynamically allocating memory. We can enter the data into buffer and read data into buffer by using pointers. We use a count variable to determine whether the data is there in the buffer or not. Circular buffer are widely used in data driven systems due to many advantages over a regular buffer.

Learn and Explore here :

LEAVE A REPLY

Please enter your comment!
Please enter your name here