Custom Data Types in C - struct, union and typedef

faribasiddiq's Avatar author of Custom Data Types in C - struct, union and typedef
This is an article on Custom Data Types in C - struct, union and typedef in C.
There are many built in data types in C. But sometimes, the built in data types are not enough to perform the required tasks. In that case, some custom data type can be built to meet the necessary requirements. In this tutorial, the following custom data types are going to be discussed:

Structure



Structure is the most commonly used custom data type. When you need to work with different variables of different data types (i.e. char, int, float ) for a specific task, you have to use structure.

Prototype:
Code:
struct tag
{
	dataType member 1;
	.....
	.....
	dataType member n;
};
Example:

Suppose an office has to make a list of all employees’ information in the office and employee information consists of employee name, designation, department, age and salary. For performing the task, a structure named employee may be declared which consists of the required information.
Code:
struct employee
{
	char name[50];
	char designation[50];
	char dept[50];
	int age;
	float salary;
};
Different section of structure: definition

Every structure consists of three parts:
  1. The keyword struct
  2. Tag
  3. Members of structure
1) struct keyword:

If the example above is considered, structure starts with the keyword struct. By this keyword, compiler is informed that a custom data type of structue is going to be declared.

2) Tag:

It is generally the name of new data type. If the previous structure is considered, the tag is employee. It informs that the following structure will be used for employee.

3) Members:

Structure members are grouped in a curly braces after the tag part. All the members which are needed to build the new data type are listed here. In previous example, new custom data type employee consists of name, designation, department, age and salary. These members are grouped along with their data type after the tag part.

Variable declaration:

The prototype of declaring a structure variable is as follows:
Code:
struct tag var1;
For the above example, you need to declare a variable like below:
Code:
struct employee john;
Here, struct employee is data type; john is variable of this data type. If more than one variable is required to declare, the code would be this way:
Code:
struct employee john, josheph;
You can declare structure variable while declaring the structure.
Code:
struct employee
{
	char name[50];
	char designation[50];
	char dept[50];
	int age;
	float salary;
} john, joseph;
Access and initialize member of a structure:

Consider another structure named birthDate. You need to keep this structure in mind for the upcoming examples. Different operations are going to be discussed using this structure.
Code:
struct birthDate
{
	int day;
	int month;
	int year;
};
Here, day, month and year are members of the structure birthdate. But how can these members be accessed and initialized? The way to access the default data types would be like below:
Code:
struct birthDate
{
	int day;
	int month;
	int year;
};

int main()
{
	
	day = 1;
	month = 1;
	year = 1980;
	printf("%d-%d-%d",day,month,year);
}
The program returns following error:
Code:
Error	1	error C2065: 'day' : undeclared identifier
Error	2	error C2065: 'month' : undeclared identifier
Error	3	error C2065: 'year' : undeclared identifier
Error	4	error C2065: 'day' : undeclared identifier
Error	5	error C2065: 'month' : undeclared identifier
Error	6	error C2065: 'year' : undeclared identifier
So the structure members cannot be accessed like built in data types. The solution is to declare a structure member at first, then to use dot(.) operator to access each member.
Code:
int main()
{
	struct birthDate johnBirthDate;
	johnBirthDate.day = 1;
	johnBirthDate.month = 1;
	johnBirthDate.year = 1980;

	printf("%d-%d-%d",johnBirthDate.day,johnBirthDate.month,johnBirthDate.year);
}
Here, structure birthDate member johnBirthDate is declared. Then, structure member is accessed using dot operator with this variable.

More ways to initialize structure variable:
Code:
struct birthDate
{
	int day;
	int month;
	int year;
}johnBirthDate = {1,1,1980};
Code:
struct birthDate
{
	int day;
	int month;
	int year;
};
struct birthDate johnBirthDate = {1,1,1980};
Data passing among structure members:

One member’s value of a structure to another member can be copied or assigned. The example given below will clarify the scenario:
Code:
int main()
{
	struct birthDate johnBirthDate;
	johnBirthDate.day = 5;
	johnBirthDate.month = johnBirthDate.day;
	johnBirthDate.year = 1980;

	printf("%d-%d-%d",johnBirthDate.day,johnBirthDate.month,johnBirthDate.year);
}
Here the statement: johnBirthDate.month = johnBirthDate.day copies data of structure member day to structure member month.

Array vs Structure:

Arrays in C work with group of variable. For example,

Code:
int employee[10];
Here, employee is an array of ten integer variables. But the thing is, only integer value in these ten variables can be stored. But one integer value is not enough to store employee information as it is necessary to store employee name, designation, department, age and salary for each employee.So we need a group of these variables.
Code:
char name[50];
char designation[50];
char dept[50];
int age;
float salary;
The concept of structure comes into action. Unlike array which groups similar data types, a structure is for different data types.

Array of structure



Till now, it has been discussed how to declare a variable of any structure and initialize the structure members using structure variable. What would you do if you need array of structure? For example, consider a situation where a database of all students of a class needs to be created. In this case, an array of a structure of student would be helpful.
Code:
struct student
{
	char* name;
	int   id;
};
If you need to declare a variable of the structure , the way is:
Code:
struct student john;
If you need to declare an array of this structure , the way is:
Code:
struct student CSE[100];
Initialization Structure Array
Code:
struct student CSE[3] = {
	"John",101,
	"Joseph", 108,
	"Maria",209
};

struct student CSE[3]= {
	{"John",101},
	{"Joseph", 108},
	{"Maria",209}
};
Access structure array elements:

An initialized array of structure has been declared. The demonstration below shows how to access the members.
Code:
int main()
{
	int loopCount;
	printf("Database of CSE students\n");
	printf("Name\tId\n");
	printf("---------------\n");
	
	for(loopCount = 0; loopCount < 3; loopCount++)
	{
		printf("%s\t%d\n",CSE[loopCount].name, CSE[loopCount].id);
	}
}
The way to access the member of the structure goes this way: CSE[loopCount].name and CSE[loopCount].id. Therefore, the way to access is :

Code:
Structure tag[arrayIndex].structure_member
Pointer to Structure:

A pointer to a structure can also be defined. The following structure gives demonstration:
Code:
struct birthDate
{
	int day;
	int month;
	int year;
};
struct birthDate *johnBirthDate;
It means johnBirthDate is a pointer of birthDate structure.

Initialization:

The way to initialize a pointer of a structure is slightly different. At first, memory for the pointer needs to be allocated. The size of the allocated memory is equal to the size of structure.

Code:
johnBirthDate = malloc(sizeof *johnBirthDate);
Access structure member using pointer:

When a pointer to a structure is declared, the structure members are accessed using arrow(->) operator, instead of dot(.) operator. Here is an example of whole process.
Code:
struct birthDate
{
	int day;
	int month;
	int year;
};

int main()
{
	struct birthDate *johnBirthDate;
	johnBirthDate = malloc(sizeof *johnBirthDate);
	johnBirthDate->day = 1;
	johnBirthDate->month = 1;
	johnBirthDate->year = 1980;

	printf("%d-%d-%d",johnBirthDate->day,johnBirthDate->month,johnBirthDate->year);

}
Everything is exactly same as the way structure variable works. The differences are – memory allocation, and use of arrow(->) operator instead of dot(.).

Nested Structure:

A structure can be declared as a member of another structure. The following structure clarifies the issue:
Code:
struct employee
{
	int empId;
	char gender;
	float salary;
};
It is assumed that the salary is not fixed for every employee. It depends on the working hours and salary per hour. So another structure for salary has to be declared.
Code:
struct salary{
	int workingHour;
	float salaryPerHOur;
};
Therefore, employee structure contains another structure named salary.
Code:
struct employee{
	int empId;
	char gender;

	struct salary{
	int workingHour;
	float salaryPerHOur;
	}employeeSalary;

}myEmployee;
Here, employeeSalary is a variable of salary structure and myEmployee is a variable of employee structure.

How will be the members of a inner structure accessed? The way is:

Code:
OuterStructure.InnerStructure.InnerStructureMember;
So, if it is needed to access workingHour and salaryPerHour of salary structure, then the way would be like this:
Code:
myEmployee.employeeSalary.workingHour;
myEmployee.employeeSalary.salaryPerHour;
Passing Structure as function Parameters:

A structure variable can be sent to a function and structure can also be returned from function.
Code:
struct student
{
	char* name;
	int   id;
};

void showStudentInfo(struct student st)
{
	printf("Student Name: %s\n",st.name);
	printf("Student Id: %d\n",st.id);
}
int main()
{
	struct student student1;
	student1.name = "John Richards";
	student1.id = 109;
	showStudentInfo(student1);
}
In the above example, a variable of student structure student1 is created in main funciton. Then its members name and id are initialized. Next the structure variable student1 is sent to showStudentInfo function. The function recieves the variable with struct student datatype. Then the members of the structure cen be accessed from showStudentInfo structure.

If the structure variable is passed to a function and the structure member value is changed, does it affect the caller function?
Code:
struct student
{
	char* name;
	int   id;
};

void showStudentInfo(struct student st)
{	
	st.name = "J. Richards";
	st.id = 110;
	printf("After changing valu in showStudentInfo\n");
	printf("Student Name: %s\n",st.name);
	printf("Student Id: %d\n",st.id);

}
int main()
{
	struct student student1;
	student1.name = "John Richards";
	student1.id = 109;
	showStudentInfo(student1);
	printf("Back to main function\n");
	printf("Student Name: %s\n",student1.name);
	printf("Student Id: %d\n",student1.id);
}
The ouput would be like this.
Code:
After changing valu in showStudentInfo
Student Name: J. Richards
Student Id: 110
Back to main function
Student Name: John Richards
Student Id: 109
So, if any structure variable is passed to any function, a local copy of that variable is made for that function. Any change of the variable in that function is limited to only that function.

The scope of members of structure can be extended. The following example would elucidate:
Code:
struct student
{
	char* name;
	int   id;
};

void showStudentInfo(struct student* st)
{
	
	st->name = "J. Richards";
	st->id = 110;
	printf("After changing valu in showStudentInfo\n");
	printf("Student Name: %s\n",st->name);
	printf("Student Id: %d\n",st->id);

}
int main()
{
	struct student student1;
	student1.name = "John Richards";
	student1.id = 109;
	showStudentInfo(&student1);
	printf("Back to main function\n");
	printf("Student Name: %s\n",student1.name);
	printf("Student Id: %d\n",student1.id);
}
Whats are the changes? The address of student1 variable has been passed to showStudentInfo function, it has been received with a structure pointer in that function and the value has been edited.

The output generated will be:
Code:
After changing valu in showStudentInfo
Student Name: J. Richards
Student Id: 110
Back to main function
Student Name: J. Richards
Student Id: 110
Values have been changed in showStudentInfo function. After returning to the main funciton, the changed value of the members is got.

Structure Memory Allocation:

A structure is considered like this:
Code:
struct employee{
	int empId;
	char gender;
	float salary;
}emp1;
How many bytes will be allocated for emp1? Size of a structure variable in memory is equal to the total size of all members of the structure.

The structure employee consists of one char, one int and one float member. If the size of int, char and float are 2,1 and 4 bytes individually, then total size of emp1 variable is = 2 + 1 + 4 = 7 bytes.

Union



Union is another commonly used custom data type beside struct. Besides, it provides some benefits on memory issue which structure does not provide. The details are discussed below:

Prototype:
Code:
union tag
{
	member 1;
	...
	....
	member n;
};
Example:

Suppose, you need to create a union of all employees’ information in an office .
Code:
union employee
{
	char name[50];
	char designation[50];
	char dept[50];
	int age;
	float salary;
};
Declaration of union is like structure except the keyword. The keyword is union for declaring a union while for structure, the keyword is struct.

Variable declaration:

It is also like structure variable declaration. Just the union keyword needs to be used instead of struct.
Code:
union employee myEmployee;
It can also be done while declaring the structure.
Code:
union employee
{
	char name[50];
	char designation[50];
	char dept[50];
	int age;
	float salary;
}myEmployee;
Access and initialize member of a union

This procedure is just same as the structure. Your concepts would clarifies if you go through structure carefully.

Structure vs union

The job which can be performed by union, can also be done by structure. So why should be union used?

The reason lies in the memory consumption. The memory required for union is less than structure in most of the cases. The clarification is given with a structure and union with same members.
Code:
struct employee{
	int empId;
	char gender;
	float salary;
}myEmployee;

union employee{
	int empId;
	char gender;
	float salary;
}myEmployee;
Here, a structure and a union are declared both consisting of same members.

Let us assume that memory consumption of int = 2 bytes, char = 1 byte, float = 4 byte. In structure, total memory consumption = 2 +1 +4 = 7 bytes. In union, total memory consumption is 4 bytes. How is that possible?

Union works in this concept: In some conditions, more than one variable is needed actually,but all the variables do not work at the same time. So the memory units needed to store the member that takes the maximum unit of memory can be taken and reused for other members.

In the above example, out of three members of union, float data type takes most memory which is 4 bytes.

Typedef



It is a way of renaming built in data type(char, int) as well as custom data type(struct, union). So, for this union, 4 bytes memory is allocated and reused for other members when needed.

Prototype:
Code:
typedef dataType newName;
Example:
Code:
typedef char word;
Here you would typedef the char data type to word. Now you can declare any char type data using word keyword instead of char.
So, if you write:
Code:
word ch;
It means the same with:
Code:
char ch;
typedef for built in data type:

You can typedef built in data types (i.e. int, float). For example:
Code:
typedef int Int16;
typedef float F32;
Then you can declare variable like this:
Code:
Int16 age, id;
F32 salary;
Typedef custom data type:

It is possible to typedef the custom data type(structure, union, enumeraton)as well as built in data type.

Typedef Structure:

The birthDate structure is considered.
Code:
struct birthDate
{
	int day;
	int month;
	int year;
};
You can typedef it to another name(Date).
Code:
typedef struct birtDate Date;
Then a variable using new name(Date) needs to be declared.
Code:
Date joiningDate;
Typedef Union:

To typedef union, the procedure is same as the structure.
Code:
union birthDate
{
	int day;
	int month;
	int year;
};
typedef union birtDate Date;
Date joiningDate;
Typedef Enumeration:

Consider the following enumeration of color .
Code:
enum color{Red,Green,Blue};
You can typedef it to another name.
Code:
typedef enum color Color;
Then the new name of the enum is to be udes to declare variable.
Code:
Color ball, leaf, sky;