diff --git a/base_3.md b/base_3.md
index 0bef38e4aa447f3ae8b304a2ee0915f9ae3c225f..f6ed7c37e981af2385461b2bab53d64076c80f3d 100644
--- a/base_3.md
+++ b/base_3.md
@@ -1,268 +1,8 @@
 % Base III
 % Inspirés des slides de F. Glück
-% 2 octobre 2019
+% 30 septembre 2020
 
-# Les tableaux (1/6)
-
-## Généralités
-
-- `C` offre uniquement des tableaux statiques
-    - Un tableau est un "bloc" de mémoire contiguë associé à un nom
-        - taille fixe déterminée à la déclaration du tableau
-        - la taille ne peut pas être changée.
-    - Pas d’assignation de tableaux.
-    - Un tableau déclaré dans une fonction ou un bloc est détruit à la sortie de celle/celui-ci
-        - $\Rightarrow$ Un tableau local à une fonction ne doit **jamais être retourné** (aussi valable pour toute variable locale)!
-- Les éléments d’un tableau sont accédés avec `[i]`{.C} où `i`{.C} est l’index de l’élément.
-- Le premier élément du tableau à l’index `0`{.C}!
-- Lorsqu’un tableau est déclaré, la taille de celui-ci doit toujours être spécifiée, sauf s’il est initialisé lors de sa déclaration.
-
-# Les tableaux (2/6)
-
-## Exemple
-
-```C
-float tab1[5]; // tableau de floats à 5 éléments
-               // ses valeurs sont indéfinies
-
-int tab2[] = {1, 2, 3}; // tableau de 3 entiers, 
-                        // taille inférée
-
-int val = tab2[1]; // val vaut 2 à présent
-
-int w = tab1[5]; // index hors des limites du tableau
-                 // comportement indéfini!
-                 // pas d'erreur du compilateur
-```
-
-<!-- TODO QUIZ:
-
-```C
-int a1[5]; // OK
-int a2[] = { 1, 2, 3 }; // OK
-int a3[4][5]; // OK
-int [] a4;  // Erreur
-int a5[];   // Erreur
-
-int[] function(void) {  // Erreur
-	int array[5];   // OK
-	return array;   // Erreur
-}
-
-void foo(int a[]) {  // OK
-	a[3] = 0;  // OK
-}
-
-void bar(void) {
-	int a[5]; // OK
-	foo(a);   // OK
-	a = a5;   // Erreur
-}
-``` -->
-
-<!-- ```C
-#include <stdio.h>
-
-int main(void) {
-	char i;
-	char a1[] = { 100,200,300,400,500 };
-	char a2[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
-	a2[10] = 42;
-
-	for (i = 0; i < 5; i++) {
-		printf("a1[%d] = %d\n", i, a1[i]);
-	}
-
-	return 0;
-}
-``` -->
-# Les tableaux (3/6)
-
-## Itérer sur les éléments d'un tableau
-
-```C
-int x[10];
-for (int i = 0; i < 10; ++i) {
-    x[i] = 0;
-}
-int j = 0;
-while (j < 10) {
-    x[j] = 1;
-    j += 1;
-}
-int j = 0;
-do {
-    x[j] = -1;
-    j += 1;
-} while (j < 9)
-```
-
-
-# Les tableaux (4/6)
-
-## Les tableaux comme argument
-
-- Un tableau est le pointeur vers sa première case.
-- Pas moyen de connaître sa taille: `sizeof()`{.C} inutile.
-- Toujours spécifier la taille d'un tableau passé en argument.
-
-    ```C
-    void foo(int tab[]) { // sans taille...
-        for (int i = 0; i < ?; ++i) {
-            // on sait pas quoi mettre pour ?
-            printf("tab[%d] = %d\n", i, tab[i]);
-        }
-    }
-    // n doit venir avant tab, [n] optionnel
-    void bar(int n, int tab[n]) {
-        for (int i = 0; i < n; ++i) {
-            printf("tab[%d] = %d\n", i, tab[i]);
-        }
-    }
-    ```
-
-# Les tableaux (5/6)
-
-## Quels sont les bugs dans ce code?
-
-```C
-#include <stdio.h>
-
-int main(void) {
-	char i;
-	char a1[] = { 100,200,300,400,500 };
-	char a2[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
-	a2[10] = 42;
-
-	for (i = 0; i < 5; i++) {
-		printf("a1[%d] = %d\n", i, a1[i]);
-	}
-
-	return 0;
-}
-```
-
-# Les tableaux (6/6)
-
-## Quels sont les bugs dans ce code?
-
-```C
-#include <stdio.h>
-
-int main(void) {
-	char i;
-    // 200, .., 500 char overflow
-	char a1[] = { 100,200,300,400,500 };
-	char a2[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
-	a2[10] = 42; // [10] out of bounds
-
-	for (i = 0; i < 5; i++) {
-		printf("a1[%d] = %d\n", i, a1[i]);
-	}
-
-	return 0;
-}
-```
-
-<!-- TODO quiz:  -->
-
-<!-- que retourne sizeof(tab[]) -->
-
-# Représentation des variables en mémoire (1/N)
-
-## La mémoire
-
-* La mémoire est:
-    - ... un ensemble de bits,
-    - ... accessible via des adresses,
-
-  +------+----------+----------+------+----------+------+------+
-  | bits | 00110101 | 10010000 | .... | 00110011 | .... | .... |
-  +======+==========+==========+======+==========+======+======+
-  | addr | 2000     | 2001     | .... | 4000     | .... | .... |
-  +------+----------+----------+------+----------+------+------+
-
-    - ... gérée par le système d'exploitation.
-    - ... séparée en deux parties: **la pile** et **le tas**.
-
-## Une variable
-
-* Une variable, `type a = valeur`{.C}, possède:
-    - un type (`char`{.C}, `int`{.C}, ...),
-    - un contenu (une séquence de bits qui encode `valeur`{.C}),
-    - une adresse mémoire (accessible via `&a`{.C}),
-    - une portée.
-
-
-# Représentation des variables en mémoire (2/N)
-
-![Les variables en mémoire.](figs/memory.svg){#fig:memory width=100%}
-
-# Les pointeurs (1/N)
-
-- Un pointeur est une adresse mémoire.
-
-    ```C
-    type *id;
-    ```
-- Pour interpréter le contenu de ce qu'il pointe, il doit être typé.
-- Un pointeur n'est rien d'autre qu'un entier (64bit sur x86-64, soit 8 octets).
-- Un pointeur peut être **déréférencé**: on accède à la valeur située à l'adresse mémoire sur laquelle il pointe.
-
-    ```C
-    char *c; // déclaration pointeur de char
-    *c = 'a'; // assign. 'a' à valeur pointée par c
-    c = 1000; // on modifie l'adresse pointée par c
-    char d = *c; // on lit la valeur pointée par c. UB!
-    ```
-
-- `NULL`{.C} (ou `0`{.C}) est la seule adresse **toujours** invalide.
-
-# Les pointeurs (2/N)
-
-![Les pointeurs, le déréférencement, et la mémoire.](figs/memory_deref.svg){#fig:memory width=100%}
-
-# Les pointeurs (3/N)
-
-- Permettent d'accéder à une valeur avec une indirection.
-
-    ```C
-    int a = 2;
-    int *b = &a;
-    *b = 7; // on met 7 dans la case pointée par b
-            // ici  a == 7 aussi
-    a = -2; // ici *b == -2 aussi
-    ```
-
-- Permettent d'avoir plusieurs chemins d'accès à une valeur.
-- Lire **et** écrire en même temps dans un bout de mémoire devient possible: **danger**.
-
-# Quiz: Les pointeurs
-
-## [Quiz: Les pointeurs](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1038526)
-
-# La fonction `sizeof()` (1/N)
-
-- La fonction `sizeof()`{.C} permet de connaître la taille en octets:
-    - d'une valeur,
-    - d'un type,
-    - d'une variable.
-- Soit `int a = 2`{.C}, sur l'architecture x86_64 que vaut:
-    - `sizeof(a)`{.C}?
-    - `sizeof(&a)`{.C}?
-- Soit `char b = 2`{.C},
-    - `sizeof(b)`{.C}?
-    - `sizeof(&b)`{.C}?
-
-# La fonction `sizeof()` (2/N)
-
-- Réponses:
-    - `sizeof(a) == 4`{.C}, `int`{.C} entier 32 bits.
-    - `sizeof(&a) == 8`{.C}, une adresse est de 64 bits.
-    - `sizeof(b) == 1`{.C}, `char`{.C} entier 8 bits.
-    - `sizeof(&b) == 8`{.C}, une adresse est de 64 bits.
-
-# Types complexes: `struct`{.C} (1/N)
+# Types complexes: `struct`{.C} (1/5)
 
 ## Généralités
 
@@ -283,7 +23,7 @@ int main(void) {
     num.im = -2.0;
     ```
 
-# Types complexes: `struct`{.C} (2/N)
+# Types complexes: `struct`{.C} (2/5)
 
 ## Simplifications
 
@@ -305,7 +45,7 @@ int main(void) {
     complex_t num2 = num; // copie
     ```
 
-# Types complexes: `struct`{.C} (3/N)
+# Types complexes: `struct`{.C} (3/5)
 
 ## Pointeurs
 
@@ -320,116 +60,93 @@ int main(void) {
 
 ![La représentation mémoire de `complex_t`.](figs/pointer_struct.svg){#fig:compilation width=100%}
 
+# Types complexes: `struct`{.C} (4/5)
 
-# Allocation dynamique de mémoire (1/N)
-
-- La fonction `malloc`{.C} permet d'allouer dynamiquement (pendant l'exécution du programme) une zone de mémoire contiguë.
-
-    ```C
-    #include <stdlib.h>
-    void *malloc(size_t size);
-    ```
-- `size`{.C} est la taille de la zone mémoire **en octets**.
-- Retourne un pointeur sur la zone mémoire ou `NULL`{.C} en cas d'échec: **toujours vérifier** que la valeur retournée est `!= NULL`{.C}.
-
-# Allocation dynamique de mémoire (2/N)
+## Initialisation
 
-- Avec l'exemple de tout à l'heure:
+- Avec le passage par **référence** on peut modifier un struct *en place*.
+- Les champs sont accessible avec le sélecteur `->`{.C}
 
     ```C
-    complex_t *num = malloc(sizeof(complex_t));
-    num->re = 1.0;  // maintenant ...
-    num->im = -1.0; // ça marche.
+    void complex_init(complex_t *num, 
+                      double re, double im) 
+    {
+        // num a déjà été allouée
+        num->re = re;
+        num->im = im;
+    }
+    int main() {
+        complex_t num; // on alloue un complexe
+        complex_init(&num, 2.0, -1.0); // on l'initialise
+    }
     ```
-- La zone mémoire **n'est pas** initialisée.
-- La mémoire doit être désallouée explicitement $\Rightarrow$ **fuites mémoires**.
-<!-- - Toujours garder un pointeur sur la mémoire allouée sinon **pointeur pendouillant**. -->
 
-![La représentation mémoire de `complex_t` et fuites.](figs/pointer_struct_ok.svg){#fig:compilation width=100%}
+# Types complexes: `struct`{.C} (5/5)
 
-# Allocation dynamique de mémoire (3/N)
+## Initialisation version copie
 
-- La fonction `free()`{.C} permet de libérer une zone préalablement allouée avec `malloc()`{.C}.
+* On peut allouer un complexe, l'initialiser et le retourner.
+* La valeur retournée peut être copiée dans une nouvelle structure.
 
     ```C
-    #include <stdlib.h>
-    void free(void *ptr);
+    complex_t complex_create(double re, double im) {
+        complex_t num;
+        num.re = re;
+        num.im = im;
+        return num;
+    }
+    int main() {
+        // on crée un complexe et on l'initialise
+        // en copiant le complexe créé par complex_create
+        // deux allocation et une copie
+        complex_t num = complex_create(2.0, -1.0); 
+    }
     ```
-- Pour chaque `malloc()`{.C} doit correspondre exactement un `free()`{.C}.
-- Si la mémoire n'est pas libérée: **fuite mémoire** (l'ordinateur plante quand il y a plus de mémoire).
-- Si la mémoire est **libérée deux** fois: seg fault.
-- Pour éviter les mauvaises surprises mettre `ptr`{.C} à `NULL`{.C}.
 
-# Allocation dynamique de mémoire (4/N)
+# Les fonctions (1/2)
 
-## Tableaux dynamiques
+## Arguments de fonctions par copie
 
-- Pour allouer un espace mémoire de 50 entiers:
+- Les arguments d'une fonction sont toujours passés **par copie**.
+- Les arguments d'une fonction ne peuvent **jamais** être modifiés.
 
     ```C
-    int *p = malloc(50 * sizeof(int));
-    ```
-- Cette espace peut alors être utilisé comme un tableau de 50 entiers:
-
-    ```C
-    for (int i = 0; i < 50; ++i) {
-        p[i] = 0;
+    void do_something(complex_t a) { // a: nouvelle variable
+        // valeur de a est une copie de x
+        // lorsque la fonction est appelée, ici -1
+        a.re += 2.0;
+        a.im -= 2.0;
+    } // a est détruite
+
+    int main() {
+        complex_t x;
+        do_something(x); // x est passé en argument
+        // x sera inchangé
     }
     ```
 
-## Arithmétique de pointeurs
-
-- On peut parcourir la mémoire différemment qu'avec l'indexation
-    
-    ```C
-    int *p = malloc(50 * sizeof(int));
-    // initialize somehow
-    double a = p[7];
-    double b = *(p + 7); // on avance de 7 "double"
-    p[0] == *p; // le pointeur est le premier élément
-    ```
-
-# Allocation dynamique de mémoire (5/N)
+* Que pourrait-on faire pour modifier `x`{.C}?
 
-## Arithmétique de pointeurs
+# Les fonctions (2/2)
 
-![L'arithmétique des pointeurs.](figs/pointer_arithmetics.svg){#fig:compilation width=100%}
+## Arguments de fonctions par référence
 
-# Allocation dynamique de mémoire (6/N)
-
-## Pointeur de pointeur
-
-- Tout comme une valeur a une adresse, un pointeur a lui-même une adresse:
+- Pour modifier un variable, il faut passer son **adresse mémoire** en argument.
+- L'adresse d'une variable, `a`{.C}, est accédée par `&a`{.C}.
+- Un **pointeur** vers une variable entière `a` le type, `int *`{.C}.
+- La syntaxe `*a`{.C} sert à **déréférencer** le pointeur (à accéder à la mémoire pointée).
 
     ```C
-    int a = 2;
-    int *b = &a;
-    int **c = &b;
-    ```
-- Chaque `*`{.C} ou `&`{.C} rajoute une indirection.
-
-# Allocation dynamique de mémoire (7/N)
-
-## Pointeur de pointeur
-
-
-![L'arithmétique des pointeurs.](figs/double_pointeur.svg){#fig:compilation height=100%}
+    void do_something(complex_t *a) { // a: un nouveau pointeur
+        // valeur de a est une copie de d'un pointeur
+        // les données pointées sont les données originales
 
-# Allocation dynamique de mémoire (8/N)
-
-- Avec `malloc()`, on peut allouer dynamiquement des tableaux de pointeurs:
-
-    ```C
-    int **p = malloc(50 * sizeof(int*));
-    for (int i = 0; i < 50; ++i) {
-        p[i] = malloc(70 * sizeof(int));
-    }
-    int a = p[5][8]; // on indexe dans chaque dimension
+        a->re += 2.0;
+        a->im -= 2.0;
+    } // le pointeur a est détruit, *a est toujours là et a été modifié
     ```
 
-- Ceci est une matrice (un tableau de tableau).
-
-# Prototypes de fonctions (1/N)
+# Prototypes de fonctions (1/3)
 
 ## Principes généraux de programmation
 
@@ -447,8 +164,7 @@ int main(void) {
 
 - Libraire `stdio.h`: `printf()`{.C}, `scanf()`{.C}, ...
 
-# Prototypes de fonctions (2/N)
-
+# Prototypes de fonctions (2/3)
 - Prototypes de fonctions nécessaires quand:
 
     1. Utilisation de fonctions dans des fichiers séparés.
@@ -457,7 +173,7 @@ int main(void) {
 - On met les prototypes des fonctions **publiques** dans des fichiers *headers*, extension `.h`.
 - Les *implémentations* des fonctions vont dans des fichier `.c`.
 
-# Prototypes de fonctions (3/N)
+# Prototypes de fonctions (3/3)
 
 ## Fichier header
 
@@ -475,13 +191,13 @@ int main(void) {
     #include "chemin/du/prototypes.h"// chemin explicite
     ```
 
-# Génération d'un exécutable (1/N)
+# Génération d'un exécutable (1/5)
 
 ## Un seul fichier source
 
 ![Étapes de génération.](figs/compilation.svg){#fig:compilation width=100%}
 
-# Génération d'un exécutable (2/N)
+# Génération d'un exécutable (2/5)
 
 ## Un seul fichier source
 
@@ -496,13 +212,13 @@ gcc proc.c -o prog
 
 Les différents codes intermédiaires sont effacés.
 
-# Génération d'un exécutable (3/N)
+# Génération d'un exécutable (3/5)
 
 ## Plusieurs fichiers sources
 
 ![Étapes de génération, plusieurs fichiers.](figs/compilation_plusieurs.svg){#fig:compilation_plusieurs width=100%}
 
-# Génération d'un exécutable (4/N)
+# Génération d'un exécutable (4/5)
 
 ::: Main
 
@@ -553,7 +269,7 @@ int sum(int tab[], int n) {
 ::::::::::::::
 
 
-# Génération d'un exécutable (4/N)
+# Génération d'un exécutable (5/5)
 
 La compilation séparée se fait en plusieurs étapes.
 
@@ -576,7 +292,7 @@ La compilation séparée se fait en plusieurs étapes.
     $ gcc main.o sum.o -o prog
     ```
 
-# Préprocesseur (1/N)
+# Préprocesseur (1/2)
 
 ## Généralités
 
@@ -601,7 +317,7 @@ La compilation séparée se fait en plusieurs étapes.
     #define NOM_MACRO(arg1, arg2, ...) [code]
     ```
 
-# Préprocesseur (2/N)
+# Préprocesseur (2/2)
 
 ## La directive `include`{.C}
 
@@ -624,5 +340,124 @@ La compilation séparée se fait en plusieurs étapes.
     #endif
     ```
 
+# Les tableaux (1/2)
+
+## Généralités
+
+- `C` offre uniquement des tableaux statiques
+    - Un tableau est un "bloc" de mémoire contiguë associé à un nom
+        - taille fixe déterminée à la déclaration du tableau
+        - la taille ne peut pas être changée.
+    - Pas d’assignation de tableaux.
+    - Un tableau déclaré dans une fonction ou un bloc est détruit à la sortie de celle/celui-ci
+        - $\Rightarrow$ Un tableau local à une fonction ne doit **jamais être retourné** (aussi valable pour toute variable locale)!
+- Les éléments d’un tableau sont accédés avec `[i]`{.C} où `i`{.C} est l’index de l’élément.
+- Le premier élément du tableau à l’index `0`{.C}!
+- Lorsqu’un tableau est déclaré, la taille de celui-ci doit toujours être spécifiée, sauf s’il est initialisé lors de sa déclaration.
+
+# Les tableaux (2/2)
+
+## Exemple
+
+```C
+float tab1[5]; // tableau de floats à 5 éléments
+               // ses valeurs sont indéfinies
+
+int tab2[] = {1, 2, 3}; // tableau de 3 entiers, 
+                        // taille inférée
+
+int val = tab2[1]; // val vaut 2 à présent
+
+int w = tab1[5]; // index hors des limites du tableau
+                 // comportement indéfini!
+                 // pas d'erreur du compilateur
+```
+
+# La ligne de commande (1/4)
+
+## Point d'entrée d'un programme
+
+- Le point d'entrée est la fonction `main()`{.C}.
+- Elle peut être déclarée de 4 façon différentes:
+    1. `void main()`{.C}.
+    2. `int main()`{.C}.
+    3. `void main(int argc, char **argv)`{.C}.
+    4. `int main(int argc, char **argv)`{.C}.
+    
+- `argc`{.C} est le nombre d'arguments passés à la ligne de commande: **le premier est celui du programme lui-même**.
+- `argv`{.C} est un tableau de chaînes de caractères passés sur la ligne de commande.
+
+# La ligne de commande (2/4)
+
+## Exemple d'utilisation
+
+Pour la fonction dans le programme `prog`
+
+```C
+int main(int argc, char **argv)
+```
+
+Pour l'exécution suivante on a 
+
+```bash
+$ ./prog -b 50 file.txt
+```
+
+```C
+argc == 4
+argv[0] == "prog"
+argv[1] == "-b"
+argv[2] == "50"
+argv[3] == "file.txt"
+```
+
+# La ligne de commande (3/4)
+
+## Conversion des arguments
+
+- Les arguments sont toujours stockés comme des **chaînes de caractère**.
+- Peu pratique si on veut manipuler des valeurs numériques.
+- Fonctions pour faire des conversions:
+
+    ```C
+    int atoi(const char *nptr);
+    long atol(const char *nptr);
+    long long atoll(const char *nptr);
+    double atof(const char *nptr);
+    int snprintf(char *str, size_t size, 
+                 const char *format, ...); 
+    // str: buffer, size: taille en octets max à copier,
+    // format: cf printf(), ret: nombre de char lus
+    ```
+
+# La ligne de commande (4/4)
+
+## Exemple d'utilisation
+
+\footnotesize
+
+```C
+#include <stdio.h>
+#include <stdlib.h>
+#include <libgen.h>
+
+int main(int argc, char **argv) {
+    if (argc != 3) {
+        char *progname = basename(argv[0]);
+        fprintf(stderr, "usage: %s name age\n", progname);
+        return EXIT_FAILURE;
+    }
 
+    char *name = argv[1];
+    int age = atoi(argv[2]);
+
+    printf("Hello %s, you are %d years old.\n", name, age);
+    return EXIT_SUCCESS;
+}
+```
+
+```bash
+$ ./prog Paul 29
+Hello Paul, you are 29 years old.
+```