Structures et fonctions en C
En C, une structure peut être passée à une fonction et retournée par une fonction exactement comme tout autre type. Il existe plusieurs stratégies de passage, chacune avec ses avantages en termes de lisibilité, de performance et de capacité à modifier les données originales.
->) et des structures (struct, initialisation, accès aux membres).| Mode de passage | Syntaxe (appel) | Copie ? | Modifie l'original ? | Recommandé pour |
|---|---|---|---|---|
| Par valeur | f(et) | Oui (copie complète) | Non | Petites structures, lecture seule |
| Par pointeur | f(&et) | Non (adresse seule) | Oui | Grandes structures, modification |
| Retour par valeur | et = f(...) | Oui (copie retournée) | — | Création/construction d'une struct |
| Retour par pointeur | p = f(&et) | Non (adresse retournée) | — | Chaînage, allocation dynamique |
1. Passage d'une structure par valeur
/* Déclaration */
void maFonction(struct NomType param);
/* Appel — la structure est copiée */
maFonction(variable);Exemple n°1 — Afficher une structure par valeur
#include <stdio.h>
struct etudiant {
char prenom[20];
int age;
};
/* Reçoit une copie — et est indépendant de et1 */
void afficher(struct etudiant et)
{
printf("Prénom : %s\n", et.prenom);
printf("Âge : %d\n", et.age);
}
int main(void)
{
struct etudiant et1 = {"Mostafa", 24};
afficher(et1); /* copie de et1 transmise */
return 0;
}Prénom : Mostafa Âge : 24
2. Passage d'une structure par pointeur
/* Déclaration */
void maFonction(struct NomType *param);
/* Appel — seule l'adresse est transmise */
maFonction(&variable);Exemple n°2 — Afficher par pointeur
#include <stdio.h>
struct etudiant {
char prenom[20];
int age;
};
/* Reçoit l'adresse — accès via -> */
void afficher(struct etudiant *et)
{
printf("Prénom : %s\n", et->prenom);
printf("Âge : %d\n", et->age);
}
int main(void)
{
struct etudiant et1 = {"Mostafa", 24};
afficher(&et1); /* adresse de et1 transmise */
return 0;
}Prénom : Mostafa Âge : 24
Exemple n°3 — Addition de nombres complexes (résultat par pointeur)
#include <stdio.h>
struct complexe {
float R; /* partie réelle */
float I; /* partie imaginaire */
};
/* c1 et c2 passés par valeur (lecture seule), res par pointeur (écriture) */
void ajouter(struct complexe c1, struct complexe c2, struct complexe *res)
{
res->R = c1.R + c2.R;
res->I = c1.I + c2.I;
}
int main(void)
{
struct complexe c1 = {2.5f, 3.0f};
struct complexe c2 = {1.24f, 4.0f};
struct complexe somme;
ajouter(c1, c2, &somme);
printf("Résultat : %.2f + %.2fi\n", somme.R, somme.I);
return 0;
}Résultat : 3.74 + 7.00i
c1 et c2 sont passées par valeur (lecture seule — on ne veut pas les modifier), tandis que res est passée par pointeur (on veut écrire le résultat dedans). C'est une technique idiomatique en C pour les fonctions qui calculent un résultat dans une variable fournie par l'appelant.const avec passage par pointeur Pour indiquer qu'une fonction reçoit un pointeur mais ne modifie pas la structure, utiliser le qualificateur const. Cela documente l'intention et laisse le compilateur détecter les modifications accidentelles :/* Lecture seule — const interdit la modification */
void afficher(const struct etudiant *et)
{
printf("%s\n", et->prenom);
/* et->age = 0; — erreur de compilation */
}
/* Modification autorisée — sans const */
void modifier(struct etudiant *et)
{
et->age += 1;
}3. Retourner une structure par valeur
Une fonction peut retourner une structure complète. Le type de retour est alors struct NomType. Une copie de la structure locale est retournée à l'appelant.
struct NomType maFonction(paramètres)
{
struct NomType var;
/* ... remplissage ... */
return var; /* retourne une copie */
}Exemple n°4 — Saisir et retourner une structure
#include <stdio.h>
struct etudiant {
char prenom[20];
int age;
};
/* Crée une struct locale, la remplit et retourne une copie */
struct etudiant saisir(void)
{
struct etudiant e;
printf("Prénom : ");
scanf("%s", e.prenom);
printf("Âge : ");
scanf("%d", &e.age);
return e; /* copie retournée vers l'appelant */
}
void afficher(const struct etudiant *et)
{
printf("\n--- Informations ---\n");
printf("Prénom : %s\n", et->prenom);
printf("Âge : %d\n", et->age);
}
int main(void)
{
struct etudiant et = saisir(); /* copie reçue et affectée */
afficher(&et);
return 0;
}Prénom : Mostafa Âge : 25 --- Informations --- Prénom : Mostafa Âge : 25
/* Dangereux — e est détruite à la fin de saisir() */
struct etudiant *saisir(void)
{
struct etudiant e;
scanf("%s", e.prenom);
return &e; /* pointeur invalide dès le retour */
}
/* Solutions correctes */
/* 1 — retourner par valeur */
struct etudiant saisir(void) { struct etudiant e; ...; return e; }
/* 2 — allouer dynamiquement */
struct etudiant *saisir(void) {
struct etudiant *e = malloc(sizeof(*e));
...; return e; /* appelant doit appeler free() */
}
/* 3 — recevoir un pointeur en paramètre */
void saisir(struct etudiant *e) { scanf("%s", e->prenom); }4. Retourner un pointeur sur une structure
Une fonction peut aussi retourner un pointeur sur une structure. Cela évite la copie et permet le chaînage d'appels. La structure pointée doit rester valide après le retour — elle doit être soit allouée dynamiquement, soit reçue en paramètre.
struct NomType *maFonction(struct NomType *param)
{
/* ... modification via param->membre ... */
return param; /* retourne l'adresse reçue */
}Exemple n°5 — Saisir via pointeur et retourner le pointeur
#include <stdio.h>
struct etudiant {
char prenom[20];
int age;
};
/* Reçoit un pointeur, le remplit, le retourne */
struct etudiant *saisir(struct etudiant *e)
{
printf("Prénom : ");
scanf("%s", e->prenom);
printf("Âge : ");
scanf("%d", &e->age);
return e;
}
int main(void)
{
struct etudiant et;
struct etudiant *p = saisir(&et); /* p pointe sur et */
printf("\nPrénom : %s\n", p->prenom);
printf("Âge : %d\n", p->age);
/* Vérification : p et &et pointent sur la même zone */
printf("p == &et : %s\n", (p == &et) ? "oui" : "non");
return 0;
}Prénom : Mostafa Âge : 26 Prénom : Mostafa Âge : 26 p == &et : oui
Exemple n°6 — Allocation dynamique et retour de pointeur
#include <stdio.h>
#include <stdlib.h>
struct etudiant {
char prenom[20];
int age;
};
/* Alloue une struct sur le tas, la remplit, retourne l'adresse */
struct etudiant *creer(const char *prenom, int age)
{
struct etudiant *e = (struct etudiant *) malloc(sizeof(struct etudiant));
if (e == NULL) return NULL;
/* Copie sécurisée du prénom */
int i;
for (i = 0 ; prenom[i] != '\0' && i < 19 ; i++)
e->prenom[i] = prenom[i];
e->prenom[i] = '\0';
e->age = age;
return e;
}
int main(void)
{
struct etudiant *e1 = creer("Mostafa", 23);
struct etudiant *e2 = creer("Dounia", 22);
if (e1) printf("e1 : %s, %d ans\n", e1->prenom, e1->age);
if (e2) printf("e2 : %s, %d ans\n", e2->prenom, e2->age);
free(e1); e1 = NULL;
free(e2); e2 = NULL;
return 0;
}e1 : Mostafa, 23 ans e2 : Dounia, 22 ans
Récapitulatif
| Mode | Déclaration fonction | Appel | Avantage | Inconvénient |
|---|---|---|---|---|
| Passage valeur | void f(struct T s) | f(var) | Sécurité (original intact) | Copie coûteuse si grande struct |
| Passage pointeur | void f(struct T *s) | f(&var) | Rapide, modifie l'original | Risque de modification accidentelle |
| Pointeur const | void f(const struct T *s) | f(&var) | Rapide + lecture seule garantie | — |
| Retour valeur | struct T f(...) | var = f(...) | Lisible, pas de pointeur fantôme | Copie à la sortie |
| Retour pointeur | struct T *f(...) | p = f(&var) | Pas de copie, chaînable | Risque de pointeur fantôme |
Discussion (0)
Soyez le premier à laisser un commentaire !
Laisser un commentaire
Votre commentaire sera visible après modération.