Une structure est un regroupement, une sorte de paquet de plusieurs données.
struct s_personne
{
int age;
char nom[20];
};
La structure s_personne est un nouveau type. Une variable de type s_personne contient deux sous-données, ici un entier age et une chaîne nom.
Cette présentation évoque les classes. On peut voir les structures comme une version simplifiée des classes.
Mais on n'a pas, pour les structures, tous les outils qui rendent les classes aussi pratiques : méthodes, privé / public, constructeur, …
Supposons que je veuille créer une variable p de type s_personne,
déclaration d'une variable p
struct s_personne p;
Nous sommes obligés de préciser le mot-clé struct pour indiquer que ce n'est pas un type de base mais un type nouveau.
Sur C playground ce n'est pas nécessaire de précisertstruct. Cela dépend probablement du compilateur : il semble que C playground utilise un compilateur C++ ce qui occasionne quelques différences. Mais en C, il faut bien préciser le mot-cléstruct, sauf si on fait ce qui suit.
Pour alléger la déclaration, on peut choisir de définir une sorte d'étiquette :
typedef struct s_personne
{
int age;
char nom[20];
} personne;
Cela signifie que l'on a attaché l'étiquette personne à la structure s_personne. Alors on peut déclaré une variable :
déclaration de p avec l'étiquette
personne p; // on utilise l'étiquette
Mais ce que l'on fait le plus souvent, c'est que l'on donne le même nom à la structure et à l'étiquette ce qui donne des déclarations un peu étrange comme ceci :
typedef struct personne
{
int age;
char nom[20];
} personne;
int main()
{
personne p;
...
return 0;
}
Pour la suite de mes exemples, je considérais la structure définie comme ci-dessus, avec le nompersonnecomme étiquette et identifiant de structure.
On parle aussi de membres.
Modifier p ou lire p c'est avant tout agir sur ses attributs age et nom.
On peut d'abord initialisé la variable de cette façon :
initialisation à la déclaration
personne p = { 72, "Robert" };
On peut aussi spécifier les attributs ce qui permet de choisir l'ordre :
initialisation à la déclaration
personne p = { .nom = "Robert", .age = 72 };
On peut aussi n'initialiser qu'une partie des attributs :
initialisation à la déclaration
personne p = { .nom = "Robert" };
Dans ce cas, l'age est par défaut à 0.
La notation est semblable à celles des attributs de classe en Python : on notera p.age et p.nom pour les deux attributs.
accès aux attributs
personne p = { .nom = "Robert", .age = 72 };
printf("Le nom est %s.\n", p.nom);
printf("L'age est %d.\n", p.age);
Il est très fréquent que l'on doive travailler sur une structure via un pointeur.
Plaçons nous dans le cas où p est toujours la variable de type personne et poi un pointeur sur p.
personne p = { .nom = "Robert", .age = 72 };
personne *poi = &p;
Vous constatez que ligne 2 que poi pointe sur l'adresse &p, c'est à dire l'adresse de la case mémoire où commence la structure p.
poccupe plusieurs cases mémoires puisqu'il est composé d'un entier et d'un tableau de caractères. Le pointeur donne l'adresse du début.
On peut accéder aux attributs de p directement à partir de poi. Pour cela, au lieu de la notation avec un ., on utilise ->. Cette flèche exprime l'idée que le pointeur est une flèche qui pointe sur une case mémoire.
personne p = { .nom = "Robert", .age = 72 };
personne *poi = &p;
printf("Le nom est %s.\n", poi->nom);
printf("L'age est %d.\n", poi->age);