Structurer vos données
Introduction
Le langage C permet de structurer les données, ce qui améliore l'organisation du code et présente plusieurs avantages, notamment pour transmettre les paramètres aux fonctions et faire évoluer votre programme.
Un premier exemple
Rien de tel qu'un exemple pour commencer. Considérons que votre programme doit gérer des coordonnées.
En C, une structure qui représente des coordonnées pourrait être implémentée ainsi :
struct Coords
{
double x;
double y;
};
Voici un premier programme permettant de manipuler cette structure :
#include <stdio.h>
struct Coords
{
double x;
double y;
};
int main(void)
{
struct Coords a; // Déclaration sans initialisation.
struct Coords b = { .x=1.0, .y=1.0 }; // Déclaration avec initialisation.
a.x = 2.0;
a.y = 2.0;
puts("Nous avons créé deux Coordonnées:");
printf("a(%f,%f)\n", a.x, a.y);
printf("b(%f,%f)\n", b.x, b.y);
return 0;
}
Le programme est déjà beaucoup plus simple que si nous n'avions pas utilisé de structure. Maintenant, comment manipuler nos coordonnées avec des fonctions ?
En transmettant des pointeurs à la place des structures entières, nous simplifions le nombre de paramètres dans nos fonctions et optimisons le programme, car la taille des paramètres sera celle d'un pointeur, même si notre structure était plus grande.
Voici une version plus évoluée du programme :
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
struct Coords
{
double x;
double y;
};
void show_coords(const char *name, struct Coords *c)
{
printf("%s(%f,%f)\n", name, c->x, c->y);
}
double distance(struct Coords *a, struct Coords *b)
{
double diffx = b->x - a->x;
double diffy = b->y - a->y;
double distance = sqrt(pow(diffx, 2.0) + pow(diffy, 2.0));
return distance;
}
void setCoords(struct Coords *c, double x, double y)
{
c->x = x;
c->y = y;
}
struct Coords* makeCoords(double x, double y)
{
struct Coords *c;
c = (struct Coords *)malloc(sizeof(struct Coords));
c->x = x;
c->y = y;
return c;
}
void freeCoords(struct Coords **c)
{
free(*c);
*c = NULL;
}
int main(void)
{
struct Coords *a = makeCoords(1.0, 1.0);
struct Coords *b = makeCoords(3.0, 3.0);
puts("Nous avons créé deux Coordonnées:");
show_coords("a", a);
show_coords("b", b);
puts("La distance entre ces deux points est de:");
printf("%f\n", distance(a, b));
puts("Informations techniques:");
printf("Adresse de a: %p\n", a);
printf("Adresse de b: %p\n", b);
freeCoords(&a);
freeCoords(&b);
puts("Après libération de la mémoire:");
printf("Adresse de a: %p\n", a);
printf("Adresse de b: %p\n", b);
return 0;
}
Cette version utilise des pointeurs pour diminuer la taille et le nombre des arguments transmis aux fonctions. Cela simplifie le programme et optimise les appels de fonctions. La fonction makeCoords() permet de créer une nouvelle coordonnée en l'initialisant et renvoie un pointeur vers celle-ci. Ainsi, chaque coordonnée est accessible via son adresse en mémoire, réduisant la taille des paramètres transmis lors de l'appel de la fonction.
Dans notre exemple, une adresse mémoire a une taille de 8 octets et une variable de type struct Coords a une taille de 16 octets. En appelant une fonction avec un pointeur, on évite de transmettre un paramètre de 16 octets, ce qui serait copié par la fonction. En transmettant l'adresse, on diminue la taille du paramètre transmis.
Et Cela serait encore plus intéressant si notre programme devait gérer des structures plus importantes en taille.
Remarque
Attention ce programme ne controle pas les erreurs pouvant se produire par exemple lors de la
réservation de la mémoire avec la fonction malloc(). C'est un exemple pour apprendre et n'est
pas un code propre à être utilisé pour un programme destiné à fonctionner dans un environnement
critique.
Aussi, il ne faut pas oublier de libérer la mémoire. Dans notre programme nous avons fournis
une fonction freeCoords() permettant de le faire proprement.