This article is the continuation of the Series on the C programming tutorial and carries the discussion on C language programming and its implementation. It aims to provide easy and practical examples for understanding the C program. In our last article, we have seen the container_of macro in C programming. In this article, we are going to see Flexible Array Member in C programming.
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.
Table of Contents
Flexible Array Member in C
Problem
Let’s take one example where I have to create one structure with a 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 decide 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. A 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 to see 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 mind while creating a flexible array of members.
- 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 more 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.
In our next article, we will start discussing the Data Structures in C programming.
You can also read the below tutorials.
Embedded Software | Firmware | Linux Devic Deriver | RTOS
Hi, I’m SLR. I am a tech blogger and an Embedded Engineer. I am always eager to learn and explore tech-related concepts. And also, I wanted to share my knowledge with everyone in a more straightforward way with easy practical examples. I strongly believe that learning by doing is more powerful than just learning by reading. I love to do experiments. If you want to help or support me on my journey, consider sharing my articles, or Buy me a Coffee! Thank you for reading my blog! Happy learning!