← HUB ✦ Holberton School — C Programming ✦

ARGC
& ARGV

Lis ce que l'utilisateur te donne.

C'EST QUOI ARGC ET ARGV ?
🎮 DÉFINITION

argc et argv sont les deux paramètres que le système d'exploitation passe à main() quand tu lances un programme depuis le terminal. Ils permettent à ton programme de recevoir des arguments en ligne de commande.

int main(int argc, char **argv)
{
    /* argc = argument count  — nombre d'arguments (toujours >= 1)
       argv = argument vector — tableau de chaînes de caractères */
    return (0);
}
🕹️ ANALOGIE GAMING

Imagine que tu lances un jeu depuis un launcher en ligne de commande : ./game --level 5 --player "Link". Le launcher compte les mots que tu as tapés (argc) et te les passe dans un tableau de chaînes (argv). Ton programme peut alors lire chaque argument comme s'il ouvrait les cases d'un inventaire.

ARGC

int argc — argument count

Nombre total d'arguments, incluant le nom du programme. Toujours ≥ 1.

ARGV

char **argv — argument vector

Tableau de pointeurs vers des chaînes. argv[0] = nom du programme. Toujours terminé par NULL.

ARGC & ARGV EN MÉMOIRE
🗺️ LAYOUT MÉMOIRE — ./prog hello 42

Commande tapée : ./prog hello 42

argc = 3 | argv (char**)
argc
INT 3 ← toujours au moins 1 (le nom du prog compte !)
argv[0]
PTR "./prog" ← nom/chemin du programme
argv[1]
PTR "hello" ← 1er argument utilisateur
argv[2]
PTR "42" ← 2ème argument (c'est une STRING, pas un int !)
argv[3]
NULL NULL ← sentinelle — argv[argc] est toujours NULL
argv[2] vaut "42" — c'est une chaîne de caractères, PAS un entier. Pour l'utiliser comme nombre : atoi(argv[2]) ou strtol(argv[2], NULL, 10).
LES DEUX FORMES DE MAIN
📦 SANS ARGUMENTS
/* Quand tu n'as pas besoin des args */
int main(void)
{
    printf("Hello World\n");
    return (0);
}

Utilise cette forme quand ton programme ne lit aucun argument — Betty approuve !

📥 AVEC ARGUMENTS
/* Quand tu lis des arguments */
int main(int argc, char **argv)
{
    /* ou : char *argv[]  — équivalent */
    return (0);
}

char **argv et char *argv[] sont strictement équivalents en paramètre de fonction.

ACCÉDER AUX ARGUMENTS
🔍 LIRE ET ITÉRER SUR ARGV
#include <stdio.h>

int main(int argc, char **argv)
{
    int i;

    /* Afficher argc */
    printf("Nombre d'arguments : %d\n", argc);

    /* Méthode 1 — boucle avec index (plus lisible) */
    i = 0;
    while (i < argc)
    {
        printf("argv[%d] = \"%s\"\n", i, argv[i]);
        i++;
    }

    /* Méthode 2 — boucle sur pointeur (sentinelle NULL) */
    char **ptr = argv;
    while (*ptr != NULL)
    {
        printf("%s\n", *ptr);
        ptr++;
    }

    /* Accès direct */
    printf("Programme : %s\n", argv[0]);  /* toujours safe */
    if (argc > 1)
        printf("1er arg : %s\n", argv[1]);  /* vérifier avant ! */

    return (0);
}
Toujours tester argc > N avant d'accéder à argv[N]. Accéder à argv[1] sans vérifier quand l'utilisateur n'a donné aucun argument → undefined behavior.
CONVERTIR LES ARGUMENTS
🔄 STRING → NOMBRE — LES FONCTIONS DE CONVERSION
#include <stdlib.h>   /* atoi, atof, strtol, strtod */
#include <stdio.h>

int main(int argc, char **argv)
{
    int    n;
    double f;
    long   l;

    if (argc < 2)
    {
        fprintf(stderr, "Usage: %s <nombre>\n", argv[0]);
        return (1);
    }

    n = atoi(argv[1]);           /* string → int (simple, pas de gestion d'erreur) */
    f = atof(argv[1]);           /* string → double */
    l = strtol(argv[1], NULL, 10); /* string → long  (gestion d'erreur possible) */

    printf("int    : %d\n", n);
    printf("double : %f\n", f);
    printf("long   : %ld\n", l);
    return (0);
}
FonctionRetourneGestion erreurUsage
atoi(str)int❌ aucuneConversion simple, Holberton OK
atof(str)double❌ aucuneFlottants
atol(str)long❌ aucuneGrands entiers
strtol(str, end, base)long✅ via errnoRobuste, base configurable
strtod(str, end)double✅ via errnoFlottants robustes
atoi("abc") retourne 0 sans signaler d'erreur. En production utilise strtol. À Holberton, atoi est généralement accepté.
VÉRIFIER LES ARGUMENTS — PATTERN HOLBERTON
🛡️ VALIDER AVANT D'UTILISER
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    /* ── Vérifier le nombre d'arguments ─────────────── */
    if (argc != 3)
    {
        fprintf(stderr, "Usage: %s <nom> <age>\n", argv[0]);
        return (1);
    }

    /* ── Utiliser les arguments validés ──────────────── */
    char *name = argv[1];
    int   age  = atoi(argv[2]);

    printf("Nom : %s\n", name);
    printf("Age : %d\n", age);
    return (0);
}

/*
 *  $ ./prog Alice 25
 *  Nom : Alice
 *  Age : 25
 *
 *  $ ./prog
 *  Usage: ./prog <nom> <age>
 */
Toujours afficher le message d'usage sur stderr avec fprintf(stderr, ...), et retourner 1 (ou EXIT_FAILURE) en cas d'erreur. C'est la convention Unix.
LES 3 BOSS — EXEMPLES PROGRESSIFS
🐣 BOSS 1 — AFFICHER TOUS LES ARGUMENTS
⚔️ LVL 1 — FACILE
#include <stdio.h>

int main(int argc, char **argv)
{
    int i = 1;   /* on commence à 1 pour sauter argv[0] */

    while (i < argc)
    {
        printf("%s\n", argv[i]);
        i++;
    }
    return (0);
}

/*
 *  $ ./prog un deux trois
 *  un
 *  deux
 *  trois
 */
⚔️ BOSS 2 — ADDITIONNER DES NOMBRES PASSÉS EN ARGS
🔥 LVL 2 — INTERMÉDIAIRE
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    int sum = 0;
    int i   = 1;

    if (argc < 2)
    {
        fprintf(stderr, "Usage: %s <n1> [n2 ...]\n", argv[0]);
        return (1);
    }
    while (i < argc)
    {
        sum += atoi(argv[i]);
        i++;
    }
    printf("Somme : %d\n", sum);
    return (0);
}

/*
 *  $ ./sum 10 20 30 5
 *  Somme : 65
 */
💀 BOSS FINAL — CALCULATRICE EN LIGNE DE COMMANDE
💀 LVL 3 — HOLBERTON STYLE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
{
    int a;
    int b;

    if (argc != 4)
    {
        fprintf(stderr, "Usage: %s <n1> <op> <n2>\n", argv[0]);
        fprintf(stderr, "  op: + - * /\n");
        return (1);
    }
    a = atoi(argv[1]);
    b = atoi(argv[3]);

    if (strcmp(argv[2], "+") == 0)
        printf("%d\n", a + b);
    else if (strcmp(argv[2], "-") == 0)
        printf("%d\n", a - b);
    else if (strcmp(argv[2], "*") == 0)
        printf("%d\n", a * b);
    else if (strcmp(argv[2], "/") == 0)
    {
        if (b == 0)
        {
            fprintf(stderr, "Error: division by zero\n");
            return (1);
        }
        printf("%d\n", a / b);
    }
    else
    {
        fprintf(stderr, "Error: unknown operator '%s'\n", argv[2]);
        return (1);
    }
    return (0);
}

/*
 *  $ ./calc 10 + 5    →  15
 *  $ ./calc 10 / 0    →  Error: division by zero
 *  $ ./calc 7 "*" 6   →  42   (guillemets pour le shell)
 */
Dans le shell, * est un caractère spécial (glob). Passe-le entre guillemets : ./calc 7 "*" 6 ou échappe-le : ./calc 7 \* 6.
ERREURS CLASSIQUES — ❌ vs ✅
❌ MAUVAIS
/* Accéder sans vérifier */
int main(int argc, char **argv)
{
    printf("%s\n", argv[1]);
    /* ❌ si pas d'arg → segfault */
}

/* Utiliser argv[1] comme int direct */
int n = argv[1]; /* ❌ c'est un char* ! */

/* Modifier argv[0] */
argv[0][0] = 'X';
/* ❌ comportement indéfini */

/* Oublier argc dans la signature */
int main(char **argv)
/* ❌ signature invalide */
✅ CORRECT
/* Toujours vérifier argc */
int main(int argc, char **argv)
{
    if (argc < 2)
        return (1);
    printf("%s\n", argv[1]); /* ✅ */
}

/* Convertir avec atoi */
int n = atoi(argv[1]); /* ✅ */

/* Lire argv[0], pas le modifier */
printf("%s\n", argv[0]); /* ✅ */

/* Signatures valides */
int main(int argc, char **argv)
int main(int argc, char *argv[])
/* ✅ les deux sont équivalents */
TIPS & RÈGLES CRITIQUES
⚡ LES RÈGLES À NE JAMAIS OUBLIER
argv[0] = nom du programme — toujours présent

Même si tu lances ./prog sans rien d'autre, argc = 1 et argv[0] = "./prog". Le compteur part de 1, pas de 0.

argv[argc] vaut toujours NULL

C'est garanti par la norme C. Tu peux itérer avec while (*argv) ou while (argv[i]) comme alternative à compter avec argc.

Tous les arguments sont des char * (strings)

Même "42" ou "3.14" sont des chaînes. Convertis toujours avec atoi, atof ou strtol avant d'utiliser comme nombre.

Message d'erreur sur stderr, retour 1

Convention Unix : les erreurs vont sur stderr avec fprintf(stderr, ...). Retourne 1 ou EXIT_FAILURE en cas d'erreur, 0 ou EXIT_SUCCESS si tout va bien.

Les espaces séparent les arguments dans le shell

Un argument avec un espace doit être entre guillemets : ./prog "Hello World" → argv[1] = "Hello World" (1 seul argument). Sans guillemets → 2 arguments séparés.

$ ./prog "Hello World"  → argc=2, argv[1]="Hello World"
$ ./prog Hello World    → argc=3, argv[1]="Hello", argv[2]="World"
Ne jamais écrire dans argv — lecture seule

Les chaînes dans argv pointent vers la mémoire gérée par le système. Copie dans un buffer local si tu dois modifier : char buf[256]; strcpy(buf, argv[1]);

RÉSUMÉ — TOUT EN UN COUP D'ŒIL
🗺️ LA CARTE MENTALE COMPLÈTE
/*
 *  SIGNATURES VALIDES
 *  ───────────────────────────────────────────────────────────
 *  int main(void)                     ← pas d'args
 *  int main(int argc, char **argv)    ← standard
 *  int main(int argc, char *argv[])   ← équivalent
 *
 *  CE QUE CONTIENT ARGV
 *  ───────────────────────────────────────────────────────────
 *  argv[0]       = nom/chemin du programme  (toujours présent)
 *  argv[1]       = 1er argument utilisateur
 *  argv[argc-1]  = dernier argument
 *  argv[argc]    = NULL                     (sentinelle)
 *
 *  RÈGLES D'OR
 *  ───────────────────────────────────────────────────────────
 *  1. argc >= 1 TOUJOURS (argv[0] compte)
 *  2. Vérifier argc avant d'accéder à argv[N]
 *  3. argv[i] est toujours un char* — convertir avec atoi/strtol
 *  4. Erreurs → fprintf(stderr) + return (1)
 *  5. Succès  → return (0)
 *  6. Espaces dans un arg → guillemets dans le shell
 *
 *  PATTERN HOLBERTON STANDARD
 *  ───────────────────────────────────────────────────────────
 *  int main(int argc, char **argv)
 *  {
 *      if (argc != N)
 *      {
 *          fprintf(stderr, "Usage: %s \n", argv[0]);
 *          return (1);
 *      }
 *      [... utiliser argv[1] à argv[N-1] ...]
 *      return (0);
 *  }
 */