Déclaration, Prototypes et Portée des fonctions en langage C

@joekakone

Joseph Konka @joekakone

03/03/2026 · 8 min

Maîtrisez les fonctions en C : signature et prototypes, passage de paramètres par valeur, pile d'exécution, portée des variables (locales, globales, static).

Une fonction est un bloc autonome d'instructions conçu pour accomplir une tâche précise. En langage C, la conception et l'appel de fonctions obéissent à des règles rigoureuses régies par le compilateur, notamment la déclaration obligatoire des prototypes et le mécanisme de passage par valeur.


1. Anatomie d'une fonction en C#

Une définition de fonction se compose d'un en-tête (signature) et d'un corps d'instructions :

\[\underbrace{\text{type\_retour}}_{\text{Type de la donnée renvoyée}} \quad \underbrace{\text{NomDeLaFonction}}_{\text{Identificateur unique}} \quad ( \underbrace{\text{type1 param1, type2 param2, ...}}_{\text{Paramètres formels d'entrée}} )\]
Exemple complet d'une fonction de calcul
float CalculerTVA(float montantHT, float tauxPourcent)
{
    float tva = montantHT * (tauxPourcent / 100.0f);
    return tva; // Renvoie le montant calculé à l'appelant
}
  • Si la fonction ne renvoie aucune valeur, son type de retour est void.
  • Si la fonction ne prend aucun paramètre d'entrée, on spécifie (void).

2. Le rôle crucial des Prototypes de fonctions#

Le compilateur C lit votre code séquentiellement, de haut en bas. Si vous écrivez la fonction main() au début de votre fichier et que vous y appelez une fonction définie plus bas, le compilateur ne connaît ni son type de retour ni ses paramètres !

Pour remédier à cela, on sépare la déclaration (le prototype) de la définition (le corps de la fonction) :

flowchart TD
    Proto["1. Prototypes placés en haut de fichier\nInforme le compilateur de l'existence des fonctions"]
    Main["2. Fonction main()\nAppelle les fonctions en toute sécurité"]
    Def["3. Définitions des fonctions en bas\nContient le code réel des fonctions"]

    Proto --> Main --> Def
Organisation canonique d'un fichier source C
#include <stdio.h>

/* ======================================================== */
/* 1. PROTOTYPES DES FONCTIONS (Déclarations préalables)    */
/* ======================================================== */
float CalculerPerimetreRectangle(float longueur, float largeur);
void AfficherResultat(float perimetre);

/* ======================================================== */
/* 2. PROGRAMME PRINCIPAL                                   */
/* ======================================================== */
int main(void)
{
    float L = 12.5f;
    float l = 4.0f;

    float p = CalculerPerimetreRectangle(L, l);
    AfficherResultat(p);

    return 0;
}

/* ======================================================== */
/* 3. DÉFINITIONS RÉELLES DES FONCTIONS                     */
/* ======================================================== */
float CalculerPerimetreRectangle(float longueur, float largeur)
{
    return 2.0f * (longueur + largeur);
}

void AfficherResultat(float perimetre)
{
    printf("Le perimetre du rectangle est de : %.2f cm\n", perimetre);
}

3. Le passage de paramètres par valeur (Pass by Value)#

[!IMPORTANT] En C, tous les paramètres scalaires (int, float, char, etc.) sont transmis par valeur. Cela signifie que la fonction reçoit une copie indépendante de la donnée. Toute modification appliquée au paramètre à l'intérieur de la fonction n'a aucun impact sur la variable originale de l'appelant.

L'expérience classique de l'échange impossible#

Observons cette tentative d'écrire une fonction qui échange deux nombres :

Échec de l'échange par valeur
#include <stdio.h>

void EchangerFaux(int a, int b)
{
    int temporaire = a;
    a = b;
    b = temporaire;
    // Les copies locales 'a' et 'b' ont été échangées...
}

int main(void)
{
    int x = 10, y = 20;

    EchangerFaux(x, y);

    // x vaut TOUJOURS 10 et y vaut TOUJOURS 20 !
    printf("x = %d, y = %d\n", x, y); 
    return 0;
}

Pour permettre à une fonction de modifier directement une variable extérieure, il faudra lui transmettre son adresse mémoire à l'aide des pointeurs (ce que nous étudierons en détail dans la Partie 4).


4. Portée et durée de vie des variables (Scope & Lifetime)#

La visibilité et la durée de rétention en mémoire d'une variable dépendent de l'endroit et de la manière dont elle est déclarée :

graph TD
    Scope[Portée des Variables]
    Scope --> Locales[Variables Locales\nDéclarées dans un bloc { ... }\nVisibles uniquement dans ce bloc\nDétruites à la sortie]
    Scope --> Globales[Variables Globales\nDéclarées hors de toute fonction\nVisibles dans tout le fichier\nPrésentes tout au long du programme]
    Scope --> Statiques[Variables Statiques locales (static)\nDéclarées dans une fonction\nConservent leur valeur entre chaque appel !]

La variable statique locale (static)#

Le mot-clé static placé devant une variable locale indique au compilateur de ne pas détruire cette variable à la fin de la fonction. Elle conserve sa valeur d'un appel à l'autre :

Compteur d'appels avec une variable static
#include <stdio.h>

void CompterConnexion(void)
{
    // Initialisée une seule fois au tout premier appel
    static int compteur = 0; 

    compteur++;
    printf("Nombre de visites enregistrees : %d\n", compteur);
}

int main(void)
{
    CompterConnexion(); // Affiche 1
    CompterConnexion(); // Affiche 2
    CompterConnexion(); // Affiche 3

    return 0;
}

5. Mise en pratique : Calculateur de mentions académiques#

Énoncé : Développez un programme modulaire contenant : 1. Une fonction CalculerMoyenne(float n1, float n2, float n3) renvoyant la moyenne arithmétique. 2. Une fonction ObtenirMention(float moyenne) renvoyant un caractère représentant la mention : - 'T' : Très Bien (\(\ge 16.0\)) - 'B' : Bien (\(\ge 14.0\)) - 'A' : Assez Bien (\(\ge 12.0\)) - 'P' : Passable (\(\ge 10.0\)) - 'E' : Éliminé / Ajourné (\(< 10.0\)) 3. Une fonction AfficherDecision(float moyenne, char mention) qui imprime le rapport final.

??? tip "Solution complète"

#include <stdio.h>

// Prototypes
float CalculerMoyenne(float n1, float n2, float n3);
char ObtenirMention(float moyenne);
void AfficherDecision(float moyenne, char mention);

int main(void)
{
    float noteMath = 15.5f;
    float noteC = 17.0f;
    float noteBDD = 13.5f;

    float moy = CalculerMoyenne(noteMath, noteC, noteBDD);
    char ment = ObtenirMention(moy);

    AfficherDecision(moy, ment);
    return 0;
}

float CalculerMoyenne(float n1, float n2, float n3)
{
    return (n1 + n2 + n3) / 3.0f;
}

char ObtenirMention(float moyenne)
{
    if (moyenne >= 16.0f) return 'T';
    if (moyenne >= 14.0f) return 'B';
    if (moyenne >= 12.0f) return 'A';
    if (moyenne >= 10.0f) return 'P';
    return 'E';
}

void AfficherDecision(float moyenne, char mention)
{
    printf("Moyenne generale : %.2f / 20\n", moyenne);
    printf("Mention obtenue  : ");
    switch (mention)
    {
        case 'T': printf("Tres Bien\n"); break;
        case 'B': printf("Bien\n"); break;
        case 'A': printf("Assez Bien\n"); break;
        case 'P': printf("Passable\n"); break;
        default:  printf("Ajourne\n"); break;
    }
}


Vous maîtrisez les bases des fonctions. Explorons maintenant un mode d'exécution particulièrement élégant et puissant : la récursivité.

Commentaires

Inscrivez-vous à une formation complète

Voir le catalogue