C Structures
C Structures
The structure in C is a user-defined data type that can be used to group items of possibly different
types into a single type. The struct keyword is used to define the structure in the C programming
language. The items in the structure are called its member and they can be of any valid data type.
C Structure Declaration
We have to declare structure in C before using it in our program. In structure declaration, we
specify its member variables along with their datatype. We can use the struct keyword to declare
the structure in C using the following syntax:
Syntax
struct structure_name {
data_type member_name1; data_type member_name1;
....
....
};
The above syntax is also called a structure template or structure prototype and no memory is
allocated to the structure in the declaration.
C Structure Definition
To use structure in our program, we have to define its instance. We can do that by creating
variables of the structure type. We can define structure variables using two methods:
struct structure_name {
data_type member_name1;
data_type member_name1;
....
....
}variable1, varaible2, ...;
Syntax
structure_name.member1;
strcuture_name.member2;
In the case where we have a pointer to the structure, we can also use the arrow operator to access
the members.
struct Point
{
int x = 0; // COMPILER ERROR: cannot initialize members here
int y = 0; // COMPILER ERROR: cannot initialize members here
};
The reason for the above error is simple. When a datatype is declared, no memory is allocated for it.
Memory is allocated only when variables are created.
Designated Initialization allows structure members to be initialized in any order. This feature has
been added in the C99 standard.
Example of Structure in C
The following C program shows how to use structures
// Driver code
int main()
{
// variable declaration after structure
template
// initialization with initializer list and
designated
// initializer list
struct str1 var1 = { 1, 'A', 1.00,
"GeeksforGeeks" },
var2;
struct str2 var3 = { .ff = 5.00, .ii = 5, .cc
= 'a' };
return 0;
}
Output
Struct 1:
i = 1, c = A, f = 1.000000, s = GeeksforGeeks
Struct 2:
i = 1, c = A, f = 1.000000, s = GeeksforGeeks
Struct 3
i = 5, c = a, f = 5.000000
Example
// defining structure
struct str1 {
int a;
};
int main()
{
// creating structure variables using
new names
str1 var1 = { 20 };
str2 var2 = { 314 };
return 0;
}
Output
var1.a = 20
var2.x = 314
Nested Structures
C language allows us to insert one structure into another as a member. This process is called nesting
and such structures are called nested structures. There are two ways in which we can nest one
structure into another:
In this method, the structure being nested is also declared inside the parent structure.
Example
struct parent {
int member1;
struct member_str member2 {
int member_str1;
char member_str2;
...
}
...
}
In this method, two structures are declared separately and then the member structure is nested
inside the parent structure.
Example
struct member_str {
int member_str1;
char member_str2;
...
}
struct parent {
int member1;
struct member_str member2;
...
}
One thing to note here is that the declaration of the structure should always be present before its
definition as a structure member. For example, the declaration below is invalid as the struct mem is
not defined when it is declared inside the parent structure.
struct parent {
struct mem a;
};
struct mem {
int var;
};
We can access nested Members by using the same ( . ) dot operator two times as shown:
str_parent.str_child .member;
// driver code
int main()
{
struct parent var1 = { 25, 195, 'A' };
Output
var1.a = 25
var1.b.x = 195
var1.b.c = A
Structure Pointer in C
We can define a pointer that points to the structure like any other variable. Such pointers are
generally called Structure Pointers. We can access the members of the structure pointed by the
structure pointer using the ( -> ) arrow operator.
// structure declaration
struct Point {
int x, y;
};
int main()
{
struct Point str = { 1, 2 };
// p2 is a pointer to structure p1
struct Point* ptr = &str;
return 0;
}
Output
1 2
Self-Referential Structures
The self-referential structures in C are those structures that contain references to the same type as
themselves i.e. they contain a member of the type pointer pointing to the same structure type.
struct structure_name {
data_type member1; data_type member2; struct structure_name* str;
}
// C program to illustrate the self referential
structures
#include <stdio.h>
// structure template
typedef struct str {
int mem1;
int mem2;
struct str* next;
}str;
// driver code
int main()
{
str var1 = { 1, 2, NULL };
str var2 = { 10, 20, NULL };
// pointer to var1
str *ptr1 = &var1;
return 0;
}
Output
var2.mem1: 10
var2.mem2: 20
Such kinds of structures are used in different data structures such as to define the nodes of linked
lists, trees, etc.
Structure padding is the concept of adding multiple empty bytes in the structure to naturally align
the data members in the memory. It is done to minimize the CPU read cycles to retrieve different
data members in the structure.
There are some situations where we need to pack the structure tightly by removing the empty bytes.
In such cases, we use Structure Packing. C language provides two ways for structure packing:
struct str2 {
char c;
int i;
} __attribute((packed)) __; // using structure
packing
// driver code
int main()
{
Output
Size of str1: 8
Size of str2: 5
As we can see, the size of the structure is varied when structure packing is performed.
To know more about structure padding and packing, refer to this article – Structure Member
Alignment, Padding and Data Packing.
Bit Fields
Bit Fields are used to specify the length of the structure members in bits. When we know the
maximum length of the member, we can use bit fields to specify the size and reduce memory
consumption.
struct structure_name {
data_type member_name: width_of_bit-field;
};
// driver code
int main()
{
printf("Size of Str1: %d\nSize of
Str2: %d",
sizeof(struct str1),
sizeof(struct str2));
return 0;
}
Output
Size of Str1: 8
Size of Str2: 4
As we can see, the size of the structure is reduced when using the bit field to define the max size of
the member ‘a’.
Uses of Structure in C
C structures are used for the following:
1. The structure can be used to define the custom data types that can be used to create some
complex data types such as dates, time, complex numbers, etc. which are not present in the
language.
2. It can also be used in data organization where a large amount of data can be stored in
different fields.
3. Structures are used to create data structures such as trees, linked lists, etc.
4. They can also be used for returning multiple values from a function.
Limitations of C Structures
In C language, structures provide a method for packing together data of different types. A
Structure is a helpful tool to handle a group of logically related data items. However, C structures
also have some limitations.
Related Articles
variable_name.member;
variable_name: An instance of a structure or a union.
member: member associated with the created structure or union.
struct str {
int mem;
};
union un {
int mem1;
char mem2;
};
int main()
{
struct str str_name = { 12};
union un un_name;
return 0;
}
Output
Union Member 1: 9
Structure Member: 12
variable_name.member1.member2;
Example:
struct base {
struct child {
int i;
} child;
};
int main()
{
struct base s_name = { 12 };
Output
Nested Structure Variable: 12
Note: dot (.) operator can only be used with structure or unions in C language.
C typedef
The typedef is a keyword that is used to provide existing data types with a new name. The C
typedef keyword is used to redefine the name of already existing data types.
When names of datatypes become difficult to use in programs, typedef is used with user-defined
datatypes, which behave similarly to defining an alias for commands.
C typedef Syntax
typedef existing_name alias_name;
After this declaration, we can use the alias_name as if it were the real existing_name in out C
program.
Example of typedef in C
typedef long long ll;
Below is the C program to illustrate how to use typedef.
C
// Driver code
int main()
{
// using typedef name to declare
variable
ll var = 20;
printf("%ld", var);
return 0;
}
Output
20
Use of typedef in C
Following are some common uses of the typedef in C programming:
The typedef keyword gives a meaningful name to the existing data type which helps other
users to understand the program more easily.
It can be used with structures to increase code readability and we don’t have to type struct
repeatedly.
The typedef keyword can also be used with pointers to declare multiple pointers in a single
statement.
It can be used with arrays to declare any number of variables.
1. typedef struct
typedef can also be used with structures in the C programming language. A new data type can be
created and used to define the structure variable.
// C program to implement
// typedef with structures
#include <stdio.h>
#include <string.h>
// Driver code
int main()
{
stu st;
strcpy(st.name, "Kamlesh Joshi");
strcpy(st.branch, "Computer Science And
Engineering");
st.ID_no = 108;
Output
Name: Kamlesh Joshi
Branch: Computer Science And Engineering
ID_no: 108
Example:
// Driver code
int main()
{
ptr var;
*var = 20;
Output
Value of var is 20
Example:
// Driver code
int main()
{
Arr temp = { 10, 20, 30, 40 };
printf("typedef using an
array\n");
Output
typedef using an array
10 20 30 40
C typedef vs #define
The following are the major difference between the typedef and #define in C:
1. #define is capable of defining aliases for values as well, for instance, you can define 1 as ONE,
3.14 as PI, etc. Typedef is limited to giving symbolic names to types only.
2. Preprocessors interpret #define statements, while the compiler interprets typedef statements.
3. There should be no semicolon at the end of #define, but a semicolon at the end of typedef.
4. In contrast with #define, typedef will actually define a new type by copying and pasting the
definition values.
Below is the C program to implement #define:
// C program to implement
#define
#include <stdio.h>
// macro definition
#define LIMIT 3
// Driver code
int main()
{
for (int i = 0; i < LIMIT;
i++) {
printf("%d \n", i);
}
return 0;
}
Output
0
1
2
FAQs on typedef in C
1. What is typedef in C?
The C typedef statement defines an alias or a nickname for the already existing data type.
The typedef struct is the statement used to define an alias for the structure data type.
The typedef enum is used to define the alias for the enumeration data type.
Structure Member Alignment, Padding and Data Packing
In C, the structures are used as data packs. They don’t provide any data encapsulation or data
hiding features.
In this article, we will discuss the property of structure padding in C along with data alignment and
structure packing.
Historically memory is byte addressable and arranged sequentially. If the memory is arranged as a
single bank of one-byte width, the processor needs to issue 4 memory read cycles to fetch an
integer. It is more economical to read all 4 bytes of an integer in one memory cycle. To take such
advantage, the memory will be arranged as a group of 4 banks as shown in the above figure.
The memory addressing still be sequential. If bank 0 occupies an address X, bank 1, bank 2 and
bank 3 will be at (X + 1), (X + 2), and (X + 3) addresses. If an integer of 4 bytes is allocated on X
address (X is a multiple of 4), the processor needs only one memory cycle to read the entire integer.
Whereas, if the integer is allocated at an address other than a multiple of 4, it spans across two
rows of the banks as shown in the below figure. Such an integer requires two memory read cycles to
fetch the data.
A variable’s data alignment deals with the way the data is stored in these banks. For example, the
natural alignment of int on a 32-bit machine is 4 bytes. When a data type is naturally aligned, the
CPU fetches it in minimum read cycles.
Similarly, the natural alignment of a short int is 2 bytes. It means a short int can be stored in bank
0 – bank 1 pair or bank 2 – bank 3 pair. A double requires 8 bytes and occupies two rows in the
memory banks. Any misalignment of double will force more than two read cycles to
fetch double data.
Note that a double variable will be allocated on an 8-byte boundary on a 32-bit machine and
requires two memory read cycles. On a 64-bit machine, based on a number of banks,
a double variable will be allocated on the 8-byte boundary and requires only one memory read cycle.
Structure Padding in C
Structure padding is the addition of some empty bytes of memory in the structure to naturally
align the data members in the memory. It is done to minimize the CPU read cycles to retrieve
different data members in the structure.
// structure A
typedef struct
structa_tag {
char c;
short int s;
} structa_t;
// structure B
typedef struct
structb_tag {
short int s;
char c;
int i;
} structb_t;
// structure C
typedef struct
structc_tag {
char c;
double d;
int s;
} structc_t;
// structure D
typedef struct
structd_tag {
double d;
int s;
char c;
} structd_t;
Calculating the size of each structure by directly adding the size of all the members, we get:
// Alignment requirements
// (typical 32 bit machine)
// char 1 byte
// short int 2 bytes
// int 4 bytes
// double 8 bytes
// structure A
typedef struct structa_tag {
char c;
short int s;
} structa_t;
// structure B
typedef struct structb_tag {
short int s;
char c;
int i;
} structb_t;
// structure C
typedef struct structc_tag {
char c;
double d;
int s;
} structc_t;
// structure D
typedef struct structd_tag {
double d;
int s;
char c;
} structd_t;
int main()
{
printf("sizeof(structa_t) = %lu\n",
sizeof(structa_t));
printf("sizeof(structb_t) = %lu\n",
sizeof(structb_t));
printf("sizeof(structc_t) = %lu\n",
sizeof(structc_t));
printf("sizeof(structd_t) = %lu\n",
sizeof(structd_t));
return 0;
}
Output
sizeof(structa_t) = 4
sizeof(structb_t) = 8
sizeof(structc_t) = 24
sizeof(structd_t) = 16
As we can see, the size of the structures is different from those we calculated.
This is because of the alignment requirements of various data types, every member of
the structure should be naturally aligned. The members of the structure are allocated
sequentially in increasing order.
Let us analyze each struct declared in the above program. For the sake of convenience, assume every
structure type variable is allocated on a 4-byte boundary (say 0x0000), i.e. the base address of the
structure is multiple of 4 (need not necessarily always, see an explanation of structc_t).
Structure A
The structa_t first element is char which is one byte aligned, followed by short int. short int is 2
bytes aligned. If the short int element is immediately allocated after the char element, it will start
at an odd address boundary. The compiler will insert a padding byte after the char to ensure short
int will have an address multiple of 2 (i.e. 2 byte aligned). The total size of structa_t will be,
sizeof(char) + 1 (padding) + sizeof(short), 1 + 1 + 2 = 4 bytes.
Structure B
The first member of structb_t is short int followed by char. Since char can be on any byte boundary
no padding is required between short int and char, in total, they occupy 3 bytes. The next member
is int. If the int is allocated immediately, it will start at an odd byte boundary. We need 1-byte
padding after the char member to make the address of the next int member 4-byte aligned. On
total,
structc_t structc_array[3];
Assume, the base address of structc_array is 0x0000 for easy calculations. If the structc_t occupies
20 (0x14) bytes as we calculated, the second structc_t array element (indexed at 1) will be at
0x0000 + 0x0014 = 0x0014. It is the start address of the index 1 element of the array. The
double member of this structc_t will be allocated on 0x0014 + 0x1 + 0x7 = 0x001C (decimal 28)
which is not multiple of 8 and conflicts with the alignment requirements of double. As we
mentioned at the top, the alignment requirement of double is 8 bytes.
In order to avoid such misalignment, the compiler introduces alignment requirements to every
structure. It will be as that of the largest member of the structure. In our case alignment of
structa_t is 2, structb_t is 4 and structc_t is 8. If we need nested structures, the size of the largest
inner structure will be the alignment of an immediate larger structure.
In structc_t of the above program, there will be a padding of 4 bytes after the int member to make
the structure size multiple of its alignment. Thus the size of (structc_t) is 24 bytes. It guarantees
correct alignment even in arrays.
Structure D
In a similar way, the size of the structure D is :
By now, it may be clear that padding is unavoidable. There is a way to minimize padding. The
programmer should declare the structure members in their increasing/decreasing order of size. An
example is structd_t given in our code, whose size is 16 bytes in lieu of 24 bytes of structc_t.
Most of the compilers provide nonstandard extensions to switch off the default padding like
pragmas or command line switches. Consult the documentation of the respective compiler for more
details.
or
struct name {
...
}__attribute__((packed)) ;
// structure A
typedef struct structa_tag {
char c;
short int s;
} structa_t;
// structure B
typedef struct structb_tag {
short int s;
char c;
int i;
} structb_t;
// structure C
typedef struct structc_tag {
char c;
double d;
int s;
} structc_t;
// structure D
typedef struct structd_tag {
double d;
int s;
char c;
} structd_t;
int main()
{
printf("sizeof(structa_t) = %lu\n",
sizeof(structa_t));
printf("sizeof(structb_t) = %lu\n",
sizeof(structb_t));
printf("sizeof(structc_t) = %lu\n",
sizeof(structc_t));
printf("sizeof(structd_t) = %lu\n",
sizeof(structd_t));
return 0;
}
Output
sizeof(structa_t) = 3
sizeof(structb_t) = 7
sizeof(structc_t) = 13
sizeof(structd_t) = 13
Yes. The stack is also memory. The system programmer should load the stack pointer with a
memory address that is properly aligned. Generally, the processor won’t check stack alignment, it is
the programmer’s responsibility to ensure proper alignment of stack memory. Any misalignment
will cause run-time surprises.
For example, if the processor word length is 32-bit, the stack pointer also should be aligned to be a
multiple of 4 bytes.
2. If char data is placed in a bank other than bank 0, it will be placed on the wrong data
lines during memory reading. How the processor handles char type?
Usually, the processor will recognize the data type based on instruction (e.g. LDRB on an ARM
processor). Depending on the bank it is stored, the processor shifts the byte onto the least significant
data lines.
3. When arguments are passed on the stack, are they subjected to alignment?
Yes. The compiler helps the programmer in making proper alignment. For example, if a 16-bit
value is pushed onto a 32-bit wide stack, the value is automatically padded with zeros out to 32
bits. Consider the following program.
The output will be 4 on a 32-bit machine. It is because each character occupies 4 bytes due to
alignment requirements.
It depends on the processor architecture. If the access is misaligned, the processor automatically
issues sufficient memory read cycles and packs the data properly onto the data bus. The penalty is
on performance. Whereas few processors will not have the last two address lines, which means there
is no way to access the odd byte boundary. Every data access must be aligned (4 bytes) properly.
Misaligned access is a critical exception on such processors. If the exception is ignored, read data will
be incorrect and hence the results.
Yes. Compilers provide non-standard extensions for such needs. For example, __alignof() in Visual
Studio helps in getting the alignment requirements of data type. Read MSDN for details.
It is important to note that most of the processors will have a math co-processor, called Floating
Point Unit (FPU). Any floating point operation in the code will be translated into FPU instructions.
The main processor is nothing to do with floating-point execution. All this will be done behind the
scenes.
As per standard, the double type will occupy 8 bytes. And, every floating point operation performed
in FPU will be of 64-bit length. Even float types will be promoted to 64 bits prior to execution.
The 64-bit length of FPU registers forces double type to be allocated on an 8-byte boundary. I am
assuming (I don’t have concrete information) in the case of FPU operations, data fetch might be
different, I mean the data bus since it goes to FPU. Hence, the address decoding will be different for
double types (which are expected to be on an 8-byte boundary). It means the address decoding
circuits of the floating point unit will not have the last 3 pins.
This article is contributed by Venki. Please write comments if you find anything incorrect, or if you
want to share more information about the topic discussed above.
For the structures in C programming language from C99 standard onwards, we can declare
an array without a dimension and whose size is flexible in nature.
Such an array inside the structure should preferably be declared as the last member of the
structure and its size is variable(can be changed at runtime).
The structure must contain at least one more named member in addition to the flexible
array member.
What must be the size of the structure below?
struct student {
int stud_id;
int name_len;
int
struct_size;
char
stud_name[];
};
In the above example, the convention is that the member “stud_name” has a size of the number of
characters stored.
struct student *s =
malloc( sizeof(*s) + sizeof(char [strlen("Kartik")]));
Its structure representation is equal to:
struct student {
int stud_id;
int name_len;
int struct_size;
char stud_name[6]; // character array of
length 6
};
Example
s->stud_id = id;
s->name_len = strlen(a);
strcpy(s->stud_name, a);
// Assigning size according to size of
stud_name
// which is a copy of user provided array
a[].
s->struct_size
= (sizeof(*s)
+ sizeof(char) * strlen(s-
>stud_name));
return s;
}
// Value of Allocated_Struct_size is in
bytes here
}
// Driver Code
int main()
{
struct student* s1 = createStudent(s1, 523,
"Cherry");
struct student* s2
= createStudent(s2, 535,
"Sanjayulsha");
printStudent(s1);
printStudent(s2);
return 0;
}
Output
Student_id : 523
Stud_Name : SanjayKanna
Name_Length: 11
Allocated_Struct_size: 23
Student_id : 535
Stud_Name : Cherry
Name_Length: 6
Allocated_Struct_size: 18
Important Points
C Unions
The Union is a user-defined data type in C language that can contain elements of the different data
types just like structure. But unlike structures, all the members in the C union are stored in the
same memory location. Due to this, only one member can store data at the given instance.
Syntax of Union in C
The syntax of the union in C can be divided into three steps which are as follows:
C Union Declaration
In this part, we only declare the template of the union, i.e., we only declare the members’ names
and data types along with the name of the union. No memory is allocated to the union in the
declaration.
union union_name {
datatype member1 ;
datatype member2 ;
...
};
Keep in mind that we have to always end the union declaration with a semi-colon.
Different Ways to Define a Union Variable
We need to define a variable of the union type to start using union members. There are two
methods using which we can define a union variable.
We can access the members of a union by using the ( . ) dot operator just like structures.
var1.member1 ;
where var1 is the union variable and member1 is the member of the union.
The above method of accessing the members of the union also works for the nested unions.
var1.member1.memberA;
Here,
Initialization of Union in C
The initialization of a union is the initialization of its members by simply assigning the value to it.
var1.member1 = some_value ;
One important thing to note here is that only one member can contain some value at a given
instance of time.
Example of Union
// C Program to demonstrate how to use
union
#include <stdio.h>
// driver code
int main()
{
return 0;
}
Output
The value stored in member1 = 15
Size of Union
The size of the union will always be equal to the size of the largest member of the array. All the
less-sized elements can store the data in the same space without any overflow.
union test2 {
int x;
char y;
} Test2;
union test3 {
int arr[10];
char y;
} Test3;
// driver code
int main()
{
// finding size using sizeof()
operator
int size1 = sizeof(Test1);
int size2 = sizeof(Test2);
int size3 = sizeof(Test3);
Output
Sizeof test1: 4
Sizeof test2: 4
Sizeof test3: 40
Structure Union
The size of the structure is equal to or greater The size of the union is the
than the total size of all of its members. size of its largest member.
The structure can contain data in multiple Only one member can contain
members at the same time. data at the same time.
FAQs on C Unions
union un {
int a;
int arr[20];
}
Ans: The size of the given union is 20 x 4 bytes = 80 bytes. Even if the array is a collection of
similar data elements, it is considered to be a single entity by the C compiler.
No. We can only store data in a single member at the same time. For example in the following C
program, both x and y share the same location. If we change x, we can see the changes being
reflected in y.
int main()
{
// A union variable t
union test t;
Output
After making x = 2:
x = 2, y = 2
Unions can be useful in many situations where we want to use the same memory for two or more
members. For example, suppose we want to implement a binary tree data structure where each leaf
node has a double data value, while each internal node has pointers to two children, but no data. If
we declare this as:
struct NODE {
struct NODE*
left;
struct NODE*
right;
double data;
};
then every node requires 16 bytes, with half the bytes wasted for each type of node. On the other
hand, if we declare a node as the following, then we can save space.
struct NODE {
bool is_leaf;
union {
struct {
struct NODE*
left;
struct NODE*
right;
} internal;
double data;
} info;
};
Bit Fields in C
In C, we can specify the size (in bits) of the structure and union members. The idea of bit-field is to
use memory efficiently when we know that the value of a field or group of fields will never exceed a
limit or is within a small range. C Bit fields are used when the storage of our program is limited.
struct
{
data_type member_name : width_of_bit-field;
};
where,
data_type: It is an integer type that determines the bit-field value which is to be interpreted.
The type may be int, signed int, or unsigned int.
member_name: The member name is the name of the bit field.
width_of_bit-field: The number of bits in the bit-field. The width must be less than or equal
to the bit width of the specified type.
Consider the following declaration of date without the use of bit fields002
int main()
{
// printing size of structure
printf("Size of date is %lu bytes\n",
sizeof(struct date));
struct date dt = { 31, 12, 2014 };
printf("Date is %d/%d/%d", dt.d, dt.m,
dt.y);
}
Output
Size of date is 12 bytes
Date is 31/12/2014
The above representation of ‘date’ takes 12 bytes on a compiler whereas an unsigned int takes 4
bytes. Since we know that the value of d is always from 1 to 31, and the value of m is from 1 to
12, we can optimize the space using bit fields.
struct date
{
// month has value between 0 and 15,
// so 4 bits are sufficient for month variable.
int month : 4;
};
However, if the same code is written using signed int and the value of the fields goes beyond the bits
allocated to the variable, something interesting can happen.
int y;
};
int main()
{
printf("Size of date is %lu
bytes\n",
sizeof(struct date));
struct date dt = { 31, 12, 2014 };
printf("Date is %d/%d/%d", dt.d,
dt.m, dt.y);
return 0;
}
Output
Size of date is 8 bytes
Date is -1/-4/2014
Explanation
The output comes out to be negative. What happened behind is that the value 31 was stored in 5
bit signed integer which is equal to 11111. The MSB is a 1, so it’s a negative number and you need
to calculate the 2’s complement of the binary number to get its actual value which is what is done
internally.
By calculating 2’s complement you will arrive at the value 00001 which is equivalent to the decimal
number 1 and since it was a negative number you get a -1. A similar thing happens to 12 in which
case you get a 4-bit representation as 1100 and on calculating 2’s complement you get the value of
-4.
1. A special unnamed bit field of size 0 is used to force alignment on the next boundary.
Example: The below code demonstrates how to force alignment to the next memory boundary using
bit fields.
int main()
{
printf("Size of test1 is %lu bytes\n",
sizeof(struct test1));
printf("Size of test2 is %lu bytes\n",
sizeof(struct test2));
return 0;
}
Output
Size of test1 is 4 bytes
Size of test2 is 8 bytes
2. We cannot have pointers to bit field members as they may not start at a byte boundary.
Example: The below code demonstrates that taking the address of a bit field member directly is not
allowed.
// C program to demonstrate that the pointers
cannot point
// to bit field members
#include <stdio.h>
struct test {
unsigned int x : 5;
unsigned int y : 5;
unsigned int z;
};
int main()
{
struct test t;
Output
Example: The below code demonstrates the usage of bit fields within a structure and assigns an out-
of-range value to one of the bit field members.
struct test {
// Bit-field member x with 2 bits
unsigned int x : 2;
// Bit-field member y with 2 bits
unsigned int y : 2;
// Bit-field member z with 2 bits
unsigned int z : 2;
};
int main()
{
// Declare a variable t of type struct test
struct test t;
// Assign the value 5 to x (2 bits)
t.x = 5;
return 0;
}
Output
Implementation-Dependent
Example: The below C program defines an array of bit fields and fails in the compilation.
int main() {}
Output
Q1. Predict the output of the following program. Assume that unsigned int takes 4 bytes
and long int takes 8 bytes.
Ans:
#include <stdio.h>
struct test {
// Unsigned integer member x
unsigned int x;
// Bit-field member y with
33 bits
unsigned int y : 33;
// Unsigned integer member z
unsigned int z;
};
int main()
{
// Print the size of struct
test
printf("%lu", sizeof(struct
test));
return 0;
}
Error:
Ans:
#include <stdio.h>
struct test {
// Unsigned integer member x
unsigned int x;
// Bit-field member y with 33 bits
long int y : 33;
// Unsigned integer member z
unsigned int z;
};
int main()
{
// Declare a variable t of type struct
test
struct test t;
// Pointer to unsigned int, pointing to
member x
unsigned int* ptr1 = &t.x;
// Pointer to unsigned int, pointing to
member z
unsigned int* ptr2 = &t.z;
return 0;
}
Output
4
Ans:
#include <stdio.h>
union test {
// Bit-field member x with 3 bits
unsigned int x : 3;
// Bit-field member y with 3 bits
unsigned int y : 3;
// Regular integer member z
int z;
};
int main()
{
// Declare a variable t of type union test
union test t;
// Assign the value 5 to x (3 bits)
t.x = 5;
// Assign the value 4 to y (3 bits)
t.y = 4;
// Assign the value 1 to z (32 bits)
t.z = 1;
// Print the values of x, y, and z
printf("t.x = %d, t.y = %d, t.z = %d", t.x,
t.y, t.z);
return 0;
}
Output
t.x = 1, t.y = 1, t.z = 1
Defining a structure: To define a structure, you must use the struct statement. The struct statement
defines a new data type, with more than or equal to one member. The format of the struct
statement is as follows:
(OR)
Defining a Union: To define a union, you must use the union statement in the same way as you did
while defining a structure. The union statement defines a new data type with more than one
member for your program. The format of the union statement is as follows:
(OR)
Example
// C program to illustrate differences
// between structure and Union
#include <stdio.h>
#include <string.h>
// declaring structure
struct struct_example {
int integer;
float decimal;
char name[20];
};
// declaring union
union union_example {
int integer;
float decimal;
char name[20];
};
void main()
{
// creating variable for structure
// and initializing values difference
// six
struct struct_example s = { 18, 38,
"geeksforgeeks" };
// difference five
printf("\n Accessing all members at a
time:");
s.integer = 183;
s.decimal = 90;
strcpy(s.name, "geeksforgeeks");
u.integer = 183;
u.decimal = 90;
strcpy(u.name, "geeksforgeeks");
printf("\nstructure data:");
s.integer = 240;
printf("\ninteger: %d", s.integer);
s.decimal = 120;
printf("\ndecimal: %f", s.decimal);
u.decimal = 120;
printf("\ndecimal: %f", u.decimal);
// difference four
printf("\nAltering a member value:\n");
s.integer = 1218;
printf("structure data:\n integer: %d\n "
" decimal: %.2f\n name: %s\n",
s.integer, s.decimal, s.name);
u.integer = 1218;
printf("union data:\n integer: %d\n"
" decimal: %.2f\n name: %s\n",
u.integer, u.decimal, u.name);
}
Output
structure data:
integer: 18
decimal: 38.00
name: geeksforgeeks
union data:
integer: 18
decimal: 0.00
name:
sizeof structure : 28
sizeof union : 20
union data:
integer: 1801807207
decimal: 277322871721159507258114048.00
name: geeksforgeeks
union data:
integer: 240
decimal: 120.000000
name: C programming
Note: Structures are better than unions since memory is shared in a union which
results in a bit of ambiguity. But technically speaking, unions are better in that they
help save a lot of memory, resulting in the overall advantage over structures in the
long run.
Quiz on structures and Union.
int main()
{
struct Scope x, y;
x.num = 65;
y.alpha = 'A';
return 0;
}
Remember that we can only access one member of a union at a time. If another member is assigned
the previous member will be wiped out from the union.
Output
x.alpha = A, x.num = 65
int main()
{
struct Scope x;
x.num = 65;
x.alpha = 'B';
return 0;
}
Output
x.alpha = B, x.num = 65
What about C++?
Anonymous Unions and Structures are NOT part of C++ 11 standard, but most of the C++
compilers support them. Since this is a C only feature, the C++ implementations don’t allow to
anonymous struct/union to have private or protected members, static members, and functions.
Hereby mistake, the state of wed is 2, it should be 3. Please refer to the same example below for a better understanding.
// Or
int main()
{
enum week day;
day = Wed;
printf("%d",day);
return 0;
}
Output:
2
In the above example, we declared “day” as the variable and the value of “Wed” is allocated to day,
which is 2. So as a result, 2 is printed.
Another example of enumeration is:
int main()
{
int i;
for (i=Jan; i<=Dec; i++)
printf("%d ", i);
return 0;
}
Output:
0 1 2 3 4 5 6 7 8 9 10 11
In this example, the for loop will run from i = 0 to i = 11, as initially the value of i is Jan which is 0
and the value of Dec is 11.
Interesting facts about initialization of enum.
1. Two enum names can have same value. For example, in the following C program both ‘Failed’ and
‘Freezed’ have same value 0.
#include <stdio.h>
enum State {Working = 1, Failed = 0,
Freezed = 0};
int main()
{
printf("%d, %d, %d", Working, Failed,
Freezed);
return 0;
}
Output:
1, 0, 0
2. If we do not explicitly assign values to enum names, the compiler by default assigns values
starting from 0. For example, in the following C program, sunday gets value 0, monday gets 1, and
so on.
#include <stdio.h>
enum day {sunday, monday, tuesday, wednesday, thursday,
friday, saturday};
int main()
{
enum day d = thursday;
printf("The day number stored in d is %d", d);
return 0;
}
Output:
#include <stdio.h>
enum day {sunday = 1, monday, tuesday = 5,
wednesday, thursday = 10, friday,
saturday};
int main()
{
printf("%d %d %d %d %d %d %d", sunday,
monday, tuesday,
wednesday, thursday, friday,
saturday);
return 0;
}
Output:
1 2 5 6 10 11 12
4. The value assigned to enum names must be some integral constant, i.e., the value must be in
range from minimum possible integer value to maximum possible integer value.
5. All enum constants must be unique in their scope. For example, the following program fails in
compilation.
Output:
#include <stdio.h>
enum day {sunday = 1, tuesday, wednesday, thursday,
friday, saturday};
int main()
{
enum day d = thursday;
printf("The day number stored in d is %d", d);
return 0;
}
Program 2:
#include <stdio.h>
enum State {WORKING = 0, FAILED, FREEZED};
enum State currState = 2;
enum State FindState() {
return currState;
}
int main() {
(FindState() == WORKING)? printf("WORKING"):
printf("NOT WORKING");
return 0;
}
Enum vs Macro
We can also use macros to define names constants. For example we can define ‘Working’ and ‘Failed’
using following macro.
#define
Working 0
#define Failed
1
#define
Freezed 2
There are multiple advantages of using enum over macro when many related named constants have
integral values.
a) Enums follow scope rules.
b) Enum variables are automatically assigned values. Following is simpler
CPP
C Structures
dot (.) Operator in C
C typedef
Structure Member Alignment, Padding and Data Packing
Flexible Array Members in a Structure in C
C Unions
Bit Fields in C
Difference Between Structure and Union in C
Anonymous Union and Structure in C
Enumeration (or enum) in C