← HUB ✦ Holberton School — C Programming ✦

VARIADIC
FUNCTIONS

Le guide ultime du débutant

LVL 3
C'EST QUOI UNE VARIADIC FUNCTION ?
🎮 DÉFINITION

Une variadic function est une fonction qui accepte un nombre variable d'arguments. Tu ne sais pas à l'avance combien de paramètres elle va recevoir !

Tu les reconnais à leurs ... dans la déclaration — appelés les ellipses.

/* Prototype d'une variadic function */
int ma_fonction(int count, ...);
🕹️ ANALOGIE GAMING

Imagine que tu joues à un RPG et que tu as un coffre magique (le personnage/la fonction). Ce coffre peut contenir autant d'items que tu veux : une épée, 3 potions, 7 flèches... Tu ne sais pas à l'avance ce qu'il va recevoir. C'est exactement ça une variadic function : elle accepte tous les items qu'on lui donne !

La variadic function la plus connue en C ? printf() ! Elle accepte une chaîne de format, puis autant d'arguments que tu veux.
LE HEADER INDISPENSABLE
📦 #include <stdarg.h>

Tout se passe dans ce header. Il contient toutes les macros dont tu as besoin pour manipuler les arguments variables.

#include <stdarg.h>  /* OBLIGATOIRE pour les variadic functions */
🕹️ ANALOGIE GAMING

C'est ton inventaire. Sans l'ouvrir (#include), tu ne peux pas accéder aux outils pour fouiller dans les arguments. Ce header est ton Bag of Holding de D&D !

LES 4 MACROS — TON SKILL TREE
🌳 SKILL TREE DES MACROS
va_list — Le sac à dos

Déclare une variable qui contiendra les arguments variables. C'est ton pointeur vers les args.

va_start — Ouvre le sac

Initialise la va_list. Pointe sur le premier argument variable. Doit être appelé AVANT va_arg.

va_arg — Récupère un item du sac

Récupère le prochain argument dans la liste. Tu dois lui dire le type attendu.

va_end — Ferme le sac

Nettoie la va_list. TOUJOURS appeler avant de quitter la fonction. C'est ton free() des va_list.

MACRO SYNTAXE RÔLE RETOURNE
va_list va_list args; Déclare la variable liste d'args type spécial
va_start va_start(args, last_named); Initialise args après le dernier param nommé void
va_arg va_arg(args, type); Récupère l'arg suivant du type donné valeur du type
va_end va_end(args); Libère / nettoie la va_list void
va_copy va_copy(dest, src); Copie une va_list dans une autre void
STRUCTURE D'UNE VARIADIC FUNCTION
🗺️ LE SQUELETTE — À MÉMORISER
#include <stdarg.h>

type_retour nom_fonction(type param_fixe, ...) /* 1. Déclaration avec ... */
{
    va_list args;                        /* 2. Déclare le "sac à dos" */
    va_start(args, param_fixe);          /* 3. Ouvre le sac après le dernier param fixe */

    /* 4. Boucle pour récupérer chaque argument */
    while (/* condition d'arrêt */)
    {
        int val = va_arg(args, int);     /* 5. Récupère un int du sac */
    }

    va_end(args);                         /* 6. Ferme le sac — TOUJOURS ! */
    return (résultat);
}
EXEMPLES CONCRETS — LES BOSS FIGHTS
⚔️ BOSS 1 — SOMME DE N ENTIERS
⭐ LVL 1 — Facile

Additionne un nombre inconnu d'entiers. Le premier argument dit combien il y en a.

#include <stdarg.h>
#include <stdio.h>

int sum_them_all(int n, ...)
{
    va_list args;
    int     sum = 0;
    int     i;

    va_start(args, n);
    i = 0;
    while (i < n)
    {
        sum += va_arg(args, int);   /* Récupère chaque int */
        i++;
    }
    va_end(args);
    return (sum);
}

int main(void)
{
    printf("%d\n", sum_them_all(4, 10, 20, 30, 40)); /* 100 */
    printf("%d\n", sum_them_all(2, 5, 5));          /* 10  */
    return (0);
}
🕹️ ANALOGIE GAMING

C'est comme ramasser des pièces dans Mario. n te dit combien de pièces il y a sur le chemin. Ensuite tu les ramasses une par une avec va_arg et tu les additionnes dans ton compteur sum.

🐲 BOSS 2 — AFFICHE N STRINGS
⭐⭐ LVL 2 — Intermédiaire

Affiche un nombre variable de chaînes de caractères.

#include <stdarg.h>
#include <stdio.h>

void print_strings(int count, ...)
{
    va_list args;
    char   *str;
    int     i;

    va_start(args, count);
    i = 0;
    while (i < count)
    {
        str = va_arg(args, char *);  /* Type : char * !! */
        printf("%s\n", str);
        i++;
    }
    va_end(args);
}

int main(void)
{
    print_strings(3, "Zelda", "Link", "Ganon");
    return (0);
}
Attention ! Le type passé à va_arg doit correspondre exactement à ce qu'on a envoyé. char * pour une string, int pour un entier, double pour un flottant (jamais float seul !).
👑 BOSS FINAL — MINI _PRINTF
⭐⭐⭐ LVL 3 — Hard (Holberton style)

Gère les specifiers %d et %s comme le vrai printf.

#include <stdarg.h>
#include <stdio.h>

void my_printf(const char *fmt, ...)
{
    va_list args;
    int     i = 0;

    va_start(args, fmt);
    while (fmt[i])
    {
        if (fmt[i] == '%' && fmt[i + 1])
        {
            i++;
            if (fmt[i] == 'd')
                printf("%d", va_arg(args, int));
            else if (fmt[i] == 's')
                printf("%s", va_arg(args, char *));
        }
        else
            putchar(fmt[i]);
        i++;
    }
    va_end(args);
}

int main(void)
{
    my_printf("Joueur: %s, Score: %d\n", "Cloud", 9999);
    return (0);
}
RÈGLES CRITIQUES — NE MEURS PAS BÊTEMENT
💀 LES GAME OVER
  • Oublier va_end → fuite mémoire
  • Mauvais type dans va_arg → comportement indéfini
  • Lire trop d'arguments → UB (Undefined Behavior)
  • Passer float à va_arg → toujours utiliser double
  • Pas de param fixe avant ... → interdit en C
🏆 LES SPEEDRUN TIPS
  • Toujours passer le nb d'args en 1er param
  • OU utiliser une valeur sentinelle (ex: NULL)
  • Compiler avec -Wall -Wextra toujours
  • char et short sont promus en int
  • float est promu en double
LES DEFAULT ARGUMENT PROMOTIONS
⬆️ PROMOTION AUTOMATIQUE DES TYPES

Quand tu passes des arguments variables, le compilateur upgrade automatiquement certains types :

char / short
⬇️
int
float
⬇️
double
int / double
✅
inchangé
Ne jamais faire va_arg(args, float) ! Utilise va_arg(args, double) car float est promu en double.
TECHNIQUE DE LA SENTINELLE
🛡️ UTILISER NULL COMME FIN DE LISTE

Plutôt que de passer le nombre d'args, tu peux terminer avec NULL comme sentinelle :

#include <stdarg.h>
#include <stdio.h>

void print_all(const char *first, ...)
{
    va_list args;
    char   *str = (char *)first;

    va_start(args, first);
    while (str != NULL)
    {
        printf("%s\n", str);
        str = va_arg(args, char *);  /* Récupère jusqu'à NULL */
    }
    va_end(args);
}

int main(void)
{
    print_all("Mario", "Luigi", "Bowser", NULL); /* NULL = fin */
    return (0);
}
🕹️ ANALOGIE GAMING

C'est comme le dernier ennemi dans un couloir. Tu avances (boucle) jusqu'à rencontrer un mur (NULL). Le NULL est ta checkpoint qui dit "stop, le niveau est terminé !"

VA_COPY — LA TECHNIQUE AVANCÉE
📋 COPIER UNE VA_LIST

Si tu dois parcourir les args deux fois, utilise va_copy :

void double_parcours(int n, ...)
{
    va_list args;
    va_list args_copy;

    va_start(args, n);
    va_copy(args_copy, args);   /* Duplique la va_list */

    /* Premier parcours avec args */
    /* ... */

    /* Deuxième parcours avec args_copy */
    /* ... */

    va_end(args_copy);          /* va_end sur la copie aussi ! */
    va_end(args);
}
va_copy crée une copie indépendante. Il faut appeler va_end sur les deux !
RÉCAP RAPIDE — TON CHEAT CODE
📝 LES 6 ÉTAPES DE VICTOIRE
1

Inclure le header

#include <stdarg.h>
2

Déclarer avec ...

int func(int n, ...);
3

Déclarer va_list

va_list args;
4

Initialiser avec va_start

va_start(args, n); — le 2e param = dernier param nommé
5

Lire avec va_arg

int val = va_arg(args, int);
6

TOUJOURS appeler va_end

va_end(args); — sinon : undefined behavior !
COMMANDES DE COMPILATION
🖥️ COMPILER TES FICHIERS
# Compilation basique
gcc -Wall -Wextra -Werror -pedantic main.c -o mon_prog

# Compiler plusieurs fichiers
gcc -Wall -Wextra -Werror main.c variadic.c -o mon_prog

# Avec le flag pedantic (recommandé Holberton)
gcc -Wall -Wextra -Werror -pedantic -std=c89 main.c -o mon_prog

# Vérifier les warnings
gcc -Wall -Wextra main.c 2>&1 | head -20
ERREURS FRÉQUENTES — ÉVITE LE GAME OVER
❌ ERREUR CLASSIQUE
/* FAUX — float dans va_arg */
float f = va_arg(args, float);
/* undefined behavior ! */
✅ LA BONNE VERSION
/* CORRECT — double dans va_arg */
double f = va_arg(args, double);
/* float est promu en double */
❌ OUBLIER VA_END
void bad_func(int n, ...)
{
    va_list args;
    va_start(args, n);
    /* ... */
    return;  /* OUBLI de va_end ! */
}
✅ TOUJOURS VA_END
void good_func(int n, ...)
{
    va_list args;
    va_start(args, n);
    /* ... */
    va_end(args);  /* TOUJOURS ! */
    return;
}
TIPS SPÉCIAL HOLBERTON
🎓 POUR TES PROJETS
/* Exemple de header pour variadic functions */
#ifndef VARIADIC_H
#define VARIADIC_H

#include <stdarg.h>

int  sum_them_all(int n, ...);
void print_numbers(int n, ...);
void print_strings(int n, ...);

#endif /* VARIADIC_H */