Flexible Array Member in C (FAM)

Before explaining the Flexible Array Member, It would be useful and easily understandable, if I explain the problem that we have.

You can also read container_of macro, pointers in c, Linux device driver tutorial, and GPS interfacing with 8051.

Flexible Array Member in C

Problem

Let’s take one example where I have to create one structure with variable size of the array. See the below snippet.

typedef struct
{
   char name[14];
   char age;
   char gender;
} NORMAL_STRUCT;

In the above structure, we declared the name with the size of 14. So it will allocate you 14 bytes for the name during the definition.

#include <stdio.h>

typedef struct
{
   char name[14];
   char age;
   char gender;
} normal_member;

int main()
{
    normal_member mike;
    
    printf("Size of the Normal structure = %ld\r\n", sizeof(mike));
    
    return 0;
}

Output

Size of the Normal structure = 16

When you print the size of the structure, it will be 16 bytes.

Scenario 1

If we use the above structure, when a user enters the name as “Mike“, it will use just 5 bytes including NULL. What will happen to the remaining 9 bytes? That another 9 bytes will be sitting idle and that is useless.

Scenario 2

What will happen when a user enters the name as “Mark Zuckerberg” which is more than 14 bytes? It may overwrite the next contiguous memory or cause the segment fault.

Solution

How do we handle these cases? Yes, I can able to hear you. Everyone may tell that, declare one char pointer inside the structure, and malloc it during the usage. Yes, I agree. But we will see the Flexible Array Member first and then decides which one is good.

What is a Flexible Array Member?

I assume that everyone knew about the arrays. So, I am directly going into the flexible arrays. When you create an array, you have to declare the array with size ( ex: char name[30] ). It won’t grow or shrink by itself. Flexible array means, we can decide the size during the execution (ex: char name[] ). So, it won’t be the fixed size. When we use this array in the structure, we can use this feature which is available in the C99 standard.

How to declare the Flexible array member?

We can declare the flexible array member like below.

typedef struct
{
   char age;
   char gender;
   char name[];
} FAM_member;

When we check the size of the array, you will be surprised by seeing the value.

#include <stdio.h>

typedef struct
{
   char age;
   char gender;
   char name[];
} FAM_member;

int main()
{
    FAM_member kite;

    printf("Size of the FAM structure = %ld\r\n", sizeof(kite));
    
    return 0;
}

Output

Size of the Normal structure = 2

OMG, it is allocating only 2 bytes? Where will we store the name? We have to allocate in the run time.

Note

We have to keep the below things in our minds while creating a flexible array member.

  • That flexible array member should be declared as the last member of the structure.
  • The structure must contain at least one more named member before the flexible array member.
Correct way  Wrong way
typedef struct
{
   char age;
   char gender;
   char name[];
} FAM_member;

 

typedef struct
{
   char name[];
   char age;
   char gender;
} FAM_member;

 

typedef struct
{
   char name[];
} FAM_member;

 

How to use flexible array members?

As of now, we have declared the flexible array member. Now, we will see how to use that. We have to create a pointer to structure like below.

FAM_member *member = NULL;

Then allocate the memory with the desired length including the structure size like below.

member = (FAM_member *) malloc( sizeof(*member) + (sizeof(char) * strlen("David")) );

Then you can use this as a normal structure and free it once you are done with the structure.

Example Program

Refer to the below program for complete usage of that FAM.

#include <stdio.h>
#include <stdlib.h>
#include<string.h> 

typedef struct
{
   char name[14];
   char age;
   char gender;
} normal_member;

typedef struct
{
   char age;
   char gender;
   char name[];
} FAM_member;

int main()
{
    normal_member normal_member;
    FAM_member *member = (FAM_member *) malloc( sizeof(*member) + (sizeof(char) * strlen("David")) );
    
    member->age    = 28;
    member->gender = 'M';
    strcpy( member->name, "David" );
    
    normal_member.age    = 28;
    normal_member.gender = 'M';
    strcpy( normal_member.name, "David" );
    
    printf( "Normal Member's Age    : %d\n"
            "Normal Member's Gender : %c\n"
            "Normal Member's Name   : %s\n\n", 
            normal_member.age,
            normal_member.gender,
            normal_member.name
          ); 
    
    printf( "FAM Member's Age    : %d\n"
            "FAM Member's Gender : %c\n"
            "FAM Member's Name   : %s\n\n", 
            member->age,
            member->gender,
            member->name
          );
          
    printf("Size of normal_member struct = %ld\n", sizeof(normal_member));
    printf("Size of FAM_member struct = %ld\n", sizeof(( sizeof(*member) + (sizeof(char) * strlen("David")) )));
    
    free(member);
    return 0;
}

Output

Normal Member's Age    : 28
Normal Member's Gender : M
Normal Member's Name   : David

FAM Member's Age    : 28
FAM Member's Gender : M
FAM Member's Name   : David

Size of normal_member struct = 16
Size of FAM_member struct = 8

So, we are way efficient than the normal structures with fixed-size arrays. There is no doubt about this. Let’s take the old debate that we had earlier.

We can add one pointer variable in the structure and allocate the memory during a run time like below.

//structure with a pointer
typedef struct
{
   char age;
   char gender;
   char *name;
} pointer_member;

pointer_member member = 
{
  .age = 28,
  .gender = 'M',
};

member.name = (char *) malloc( sizeof(char) * strlen("David") );
strcpy(member.name, "David");

free(member.name);

Yes, I agree. But why we don’t use it that way is,

  • It will consume the extra 4 or 8 bytes for the pointer variable, unlike the FAM structure.
  • The memory of the structure resides in the stack and the allocated memory for the name will reside on the heap. This affects the number of instructions required to access it.
  •  It also incurs an extra dereference every time the pointer is used.

You can also read the below tutorials.

Linux Device Driver TutorialsC Programming Tutorials
FreeRTOS TutorialsNuttX RTOS Tutorials
RTX RTOS TutorialsInterrupts Basics
I2C Protocol – Part 1 (Basics)I2C Protocol – Part 2 (Advanced Topics)
STM32 TutorialsLPC2148 (ARM7) Tutorials
PIC16F877A Tutorials8051 Tutorials
Unit Testing in C TutorialsESP32-IDF Tutorials
Raspberry Pi TutorialsEmbedded Interview Topics
Reset Sequence in ARM Cortex-M4BLE Basics
VIC and NVIC in ARMSPI – Serial Peripheral Interface Protocol
Bootloader TutorialsRaspberry PI Pico Tutorials
4.8 8 votes
Article Rating
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x