You may already asked how to create an array with different data types. Like a tuple. This is not possible, but we can create structures of data !
Structures
struct <identifier> {
<type> <identifier>; // attribute 1
<type> <identifier>; // attribute 2
...
};
This is an example creating a structure object :
#include <assert.h>
struct s_user {
char* name;
int age;
};
int main(void) {
struct s_user user1 = { "John", 34 };
assert(user1.age == 34);
return 0;
}
As you can see, we can access to the object's elements with the following syntax :
<object identifier>.<attribute identifier>
Type definition
typedef struct <struct identifier> <type identifier>;
We usually define a type for structures we create.
typedef struct s_user {
char* name;
int age;
} User;
struct s_user {
char* name;
int age;
};
typedef struct s_user User;
It's also possible to make an anonymous structure while using the first method :
typedef struct {
char* name;
int age;
} User;
Enumerations
Imagine that we want to store the user's job, we could store it into a string. But a better way to do it exists : enumerations.
typedef enum e_job {
Builder,
Dentist,
Engineer,
Fireman,
Lawyer,
Teacher,
Waiter
} Job;
We can add a Job
attribute to our User
structure :
typedef struct s_user {
char* name;
int age;
Job job;
} User;
In some language, an enumeration element can be retrieved by the Enum::Element
syntax. But in C, you directly have an access to the elements, without post fixing with the enumeration identifier.
Using enumerations is a smarter way to define something than a string object, and it takes less memory space.
int main(void) {
User user1 = { "John", 34, Builder };
printf("sizeof(User user1) == %li\n", sizeof(user1));
printf("sizeof(Job Builder) == %li\n", sizeof(Builder));
printf("sizeof(char* \"builder\") == %li\n", sizeof("builder"));
return 0;
}
sizeof(User user1) == 16
sizeof(Job Builder) == 4
sizeof(char* "builder") == 8
With enumerations, it's possible to set a value for an element in the declaration :
typedef enum {
Working = 1,
Failed = 0,
Freezed = -1
} State;
Methods with structures
The C language does not embed classes, so there are no methods. But, we can recreate this principle thanks to the pointers
User new_user(char* name, int age, Job job) {
User temp = { name, age, job };
return temp;
}
void print_user(User user) {
printf("User(%s, %i, %s)\n", user.name, user.age, job_to_string(user.job));
}
void change_user_job(User* user, Job job) {
user->job = job;
}
void free_user(User* user) {
user->name = (char*) NULL;
user->age = -1;
user->job = Null;
user = (User*) NULL;
}
What does
user-><attribute>
means ? Why we sometimes use it instead ofuser.<attribute>
?
When we manipulate a pointer of a structure object, we cannot directly access to the attributes. We have to get the pointer's pointing value (as seen in this article) :
int n = 5;
int* ptr_n = &n;
assert(*ptr_n == 5); // pointed value retrieved
So, we are supposed to do that :
(*user).job
We have to embrace user
because *user.job
cannot be done because it would mean that we want to retrieve the pointing value of job
.
But, it's a boring syntax, so the C language allows to use the ->
symbol instead, to make things easier.
(*user).job = user->job
Exercises
- Write the "
Job
element converter to string" function using a switch statement - Create an enumeration with the 7 days of the week, every element has to be assigned by its day week number. In addition to that, create the following function :
int is_weekend(DayWeek day_week);
Solutions
Write the "
Job
element converter to string" function using a switch statementchar* job_to_string(Job job) { switch (job) { case Builder: return "Builder"; case Dentist: return "Dentist"; case Engineer: return "Engineer"; case Fireman: return "Fireman"; case Lawyer: return "Lawyer"; case Teacher: return "Teacher"; case Waiter: return "Waiter"; case Null: return "(null)"; } }
Create an enumeration with the 7 days of the week, every element has to be assigned by its day of the week number. In addition of that, create the following function :
int is_weekend(DayWeek day_week);
#include <assert.h> typedef enum { Monday = 1, Tuesday = 2, Wednesday = 3, Thursday = 4, Friday = 5, Saturday = 6, Sunday = 7 } DayWeek; int is_weekend(DayWeek day_week) { // A weekday, not a day of the weekend if (day_week != 6 && day_week != 7) { return 0; } return 1; } int main() { assert(Monday == 1); assert(Sunday == 7); assert(is_weekend(Wednesday) != 1); assert(is_weekend(Saturday) == 1); return 0; }