Struct data ype
There are many situations in which many variables are related to each other, with the values stored in each variable are pieces of information belonging to one object or entity. It would be desirable to have a way to store that information in a cohesive way, without having to resort to using many unique variables with their relationship achieved through some programmer's defined naming convention. Fortunately, we have structs to allow us to link different data types together in a cohesive way.
In its simplest form a struct is a group or collection of different data types forming a compound data type. Going further on, when we combine structs and pointers, we can build more complex data structures such as linked lists and abstract data types such as stacks.
Two natural questions might arise: "Can struct's members be added or removed at program's runtime?" and "Can structs inherit members from other structs?". Those require new concepts which aren't currently covered in this site. Short answer: no.
To avoid confusion:
- A struct is not a variable, it's a compound data type;
- The difference between local and global scopes does apply to structs.
To understand structures not much more knowledge than simple variables and arrays is required
- Declaring a simple struct to store data about a person:
struct Person {
char FirstName[20];
char LastName[20];
int age;
char Gender[1];
};
We now have a new data type of the type "Person", which has four fields to store information about a person. Each one of these fields is a struct's member.
Note: we cannot declare and assign values to the struct's fields at the same time, that's because we are declaring a new data type, not a new variable.
- How to use the newly created data type:
struct person Maria;
Maria.FirstName[0] = 'M';
Maria.FirstName[1] = 'a';
Maria.FirstName[2] = 'r';
Maria.FirstName[3] = 'i';
Maria.FirstName[4] = 'a';
Maria.LastName[0] = 'D';
Maria.LastName[1] = 'o';
Maria.LastName[2] = 'l';
Maria.LastName[3] = 'o';
Maria.LastName[4] = 'r';
Maria.LastName[5] = 'e';
Maria.LastName[6] = 's';
Maria.age = 20;
Maria.Gender = 'F';
We have now declared a new variable called "Maria", with the type "person". The syntax follows the pattern: type 'dot' field's name.
Assignment: a struct can only be assigned to another if both are of the same type. If they mismatch there is no implicit conversion from one to another. This behaviour is different from, for example, int to float, where a implicit conversion takes place.
Note: structs cannot be used in expressions such as comparisons or arithmetic expressions. For example: suppose we have two new variables of the "person" type, "Maria" and "Sara", comparisons such as Maria == Sara or operations such as Maria + Sara hold no meaning for the computer. We have to tell the computer what about "Maria" or "Sara" is going to be compared or what value(s) are going to be used in an expression. Therefore, expressions such as "Maria.age > Sara.age" are valid.
- Nested struct:
char Name[20];
char Address[20];
char Code[3];
};
struct Person {char FirstName[20];
char LastName[20];
int age;
char Gender[1];
struct School Pine;
};
In C we can nest structs to create complex data types. In the above example we have declared the struct "School", which is nested in the struct "Person". Note that, inside "Person", we are not declaring the struct "School", but creating a member that is of the type "School" and is called "Pine".
- Accessing nested structs:
struct Person Maria;
Maria.Pine.Code[0] = 'X';
Maria.Pine.Code[1] = '0';
Maria.Pine.Code[2] = '0';
The syntax is pretty much the same as regular structs, just one more dot has been added.
Note: there is no rule about when to nest or, in the above example, decide whether "Person" or "School" should be at the higher level. It's the programmer's decision.
- Typedef:
typedef struct Person Per;
Per Maria;
When we work with structs it's a common practice to use typedef to make the code easier to read. What typedef does is to "replace" the syntax struct type with a shorthand. In the example above we've "replaced" the longer expression struct Person with "Per", a three letter shorthand similar to int, float, etc.
- Declaring and using an array of struct:
struct company {
char name[10];
int age;
};
struct company person[2];
person[0].name[0] = 'M';
person[0].name[1] = 'a';
person[0].name[2] = 'r';
person[0].name[3] = 'i';
person[0].name[4] = 'a';
person[0].age = 20;
person[0].name[0] = 'S';
person[0].name[1] = 'a';
person[0].name[2] = 'r';
person[0].name[3] = 'a';
person[1].age = 22;
Much like array of integers or arrays of characters we can have arrays of structures. Without the array we'd have to declare one new variable per person, with an array we have a convenient way to sequentially hold data about many persons.
- Shorter way to declare an array of struct:
struct company {
char name[10];
int age;
}
person[2];
This way we don't have to type "struct type" twice.