diff --git a/base_5.md b/base_5.md
index 0bef38e4aa447f3ae8b304a2ee0915f9ae3c225f..dbea1fe031c68f8735f1515b50776ec638ec10e9 100644
--- a/base_5.md
+++ b/base_5.md
@@ -1,174 +1,8 @@
-% Base III
+% Base V
 % Inspirés des slides de F. Glück
-% 2 octobre 2019
+% 14 octobre 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)
+# Représentation des variables en mémoire (1/2)
 
 ## La mémoire
 
@@ -194,11 +28,11 @@ int main(void) {
     - une portée.
 
 
-# Représentation des variables en mémoire (2/N)
+# Représentation des variables en mémoire (2/2)
 
 ![Les variables en mémoire.](figs/memory.svg){#fig:memory width=100%}
 
-# Les pointeurs (1/N)
+# Les pointeurs (1/3)
 
 - Un pointeur est une adresse mémoire.
 
@@ -218,11 +52,11 @@ int main(void) {
 
 - `NULL`{.C} (ou `0`{.C}) est la seule adresse **toujours** invalide.
 
-# Les pointeurs (2/N)
+# Les pointeurs (2/3)
 
 ![Les pointeurs, le déréférencement, et la mémoire.](figs/memory_deref.svg){#fig:memory width=100%}
 
-# Les pointeurs (3/N)
+# Les pointeurs (3/3)
 
 - Permettent d'accéder à une valeur avec une indirection.
 
@@ -237,11 +71,7 @@ int main(void) {
 - 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()` (1/2)
 
 - La fonction `sizeof()`{.C} permet de connaître la taille en octets:
     - d'une valeur,
@@ -254,7 +84,7 @@ int main(void) {
     - `sizeof(b)`{.C}?
     - `sizeof(&b)`{.C}?
 
-# La fonction `sizeof()` (2/N)
+# La fonction `sizeof()` (2/2)
 
 - Réponses:
     - `sizeof(a) == 4`{.C}, `int`{.C} entier 32 bits.
@@ -262,66 +92,7 @@ int main(void) {
     - `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)
-
-## Généralités
-
-- Plusieurs variables qu'on aimerait regrouper dans un seul type: `struct`{.C}.
-
-    ```C
-    struct complex { // déclaration
-        double re;
-        double im;
-    };
-
-    struct complex num; // déclaration de num
-    ```
-- Les champs sont accessible avec le sélecteur "`.`{.C}".
-
-    ```C
-    num.re = 1.0;
-    num.im = -2.0;
-    ```
-
-# Types complexes: `struct`{.C} (2/N)
-
-## Simplifications
-
-- `typedef`{.C} permet de définir un nouveau type.
-
-    ```C
-    typedef unsinged int uint;
-    typedef struct complex complex_t;
-    typedef struct complex {
-        double re, im;
-    } complex_t;
-    ```
-- L'initialisation peut aussi se faire avec
-
-    ```C
-    complex_t num = {1.0, -2.0}; // re = 1.0, im = -2.0
-    complex_t num = {.im = 1.0, .re = -2.0};
-    complex_t num = {.im = 1.0}; // argl! .re non initialisé 
-    complex_t num2 = num; // copie
-    ```
-
-# Types complexes: `struct`{.C} (3/N)
-
-## Pointeurs
-
-- Comme pour tout type, on peut avoir des pointeurs vers un `struct`{.C}.
-- Les champs sont accessible avec le sélecteur `->`{.C}
-
-    ```C
-    complex_t *num; // on crée un pointeur
-    num->re = 1.0;  // seg fault...
-    num->im = -1.0; // mémoire pas allouée.
-    ```
-
-![La représentation mémoire de `complex_t`.](figs/pointer_struct.svg){#fig:compilation width=100%}
-
-
-# Allocation dynamique de mémoire (1/N)
+# Allocation dynamique de mémoire (1/8)
 
 - La fonction `malloc`{.C} permet d'allouer dynamiquement (pendant l'exécution du programme) une zone de mémoire contiguë.
 
@@ -332,14 +103,14 @@ int main(void) {
 - `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)
+# Allocation dynamique de mémoire (2/8)
 
-- Avec l'exemple de tout à l'heure:
+- On peut allouer un `complex_t`{.C}:
 
     ```C
     complex_t *num = malloc(sizeof(complex_t));
-    num->re = 1.0;  // maintenant ...
-    num->im = -1.0; // ça marche.
+    num->re = 1.0;
+    num->im = -1.0;
     ```
 - La zone mémoire **n'est pas** initialisée.
 - La mémoire doit être désallouée explicitement $\Rightarrow$ **fuites mémoires**.
@@ -347,7 +118,7 @@ int main(void) {
 
 ![La représentation mémoire de `complex_t` et fuites.](figs/pointer_struct_ok.svg){#fig:compilation width=100%}
 
-# Allocation dynamique de mémoire (3/N)
+# Allocation dynamique de mémoire (3/8)
 
 - La fonction `free()`{.C} permet de libérer une zone préalablement allouée avec `malloc()`{.C}.
 
@@ -360,7 +131,7 @@ int main(void) {
 - 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)
+# Allocation dynamique de mémoire (4/8)
 
 ## Tableaux dynamiques
 
@@ -389,13 +160,13 @@ int main(void) {
     p[0] == *p; // le pointeur est le premier élément
     ```
 
-# Allocation dynamique de mémoire (5/N)
+# Allocation dynamique de mémoire (5/8)
 
 ## Arithmétique de pointeurs
 
 ![L'arithmétique des pointeurs.](figs/pointer_arithmetics.svg){#fig:compilation width=100%}
 
-# Allocation dynamique de mémoire (6/N)
+# Allocation dynamique de mémoire (6/8)
 
 ## Pointeur de pointeur
 
@@ -408,14 +179,14 @@ int main(void) {
     ```
 - Chaque `*`{.C} ou `&`{.C} rajoute une indirection.
 
-# Allocation dynamique de mémoire (7/N)
+# Allocation dynamique de mémoire (7/8)
 
 ## Pointeur de pointeur
 
 
 ![L'arithmétique des pointeurs.](figs/double_pointeur.svg){#fig:compilation height=100%}
 
-# Allocation dynamique de mémoire (8/N)
+# Allocation dynamique de mémoire (8/8)
 
 - Avec `malloc()`, on peut allouer dynamiquement des tableaux de pointeurs:
 
diff --git a/base_X.md b/base_X.md
new file mode 100644
index 0000000000000000000000000000000000000000..0bef38e4aa447f3ae8b304a2ee0915f9ae3c225f
--- /dev/null
+++ b/base_X.md
@@ -0,0 +1,628 @@
+% Base III
+% Inspirés des slides de F. Glück
+% 2 octobre 2019
+
+# 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)
+
+## Généralités
+
+- Plusieurs variables qu'on aimerait regrouper dans un seul type: `struct`{.C}.
+
+    ```C
+    struct complex { // déclaration
+        double re;
+        double im;
+    };
+
+    struct complex num; // déclaration de num
+    ```
+- Les champs sont accessible avec le sélecteur "`.`{.C}".
+
+    ```C
+    num.re = 1.0;
+    num.im = -2.0;
+    ```
+
+# Types complexes: `struct`{.C} (2/N)
+
+## Simplifications
+
+- `typedef`{.C} permet de définir un nouveau type.
+
+    ```C
+    typedef unsinged int uint;
+    typedef struct complex complex_t;
+    typedef struct complex {
+        double re, im;
+    } complex_t;
+    ```
+- L'initialisation peut aussi se faire avec
+
+    ```C
+    complex_t num = {1.0, -2.0}; // re = 1.0, im = -2.0
+    complex_t num = {.im = 1.0, .re = -2.0};
+    complex_t num = {.im = 1.0}; // argl! .re non initialisé 
+    complex_t num2 = num; // copie
+    ```
+
+# Types complexes: `struct`{.C} (3/N)
+
+## Pointeurs
+
+- Comme pour tout type, on peut avoir des pointeurs vers un `struct`{.C}.
+- Les champs sont accessible avec le sélecteur `->`{.C}
+
+    ```C
+    complex_t *num; // on crée un pointeur
+    num->re = 1.0;  // seg fault...
+    num->im = -1.0; // mémoire pas allouée.
+    ```
+
+![La représentation mémoire de `complex_t`.](figs/pointer_struct.svg){#fig:compilation width=100%}
+
+
+# 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)
+
+- Avec l'exemple de tout à l'heure:
+
+    ```C
+    complex_t *num = malloc(sizeof(complex_t));
+    num->re = 1.0;  // maintenant ...
+    num->im = -1.0; // ça marche.
+    ```
+- 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%}
+
+# Allocation dynamique de mémoire (3/N)
+
+- La fonction `free()`{.C} permet de libérer une zone préalablement allouée avec `malloc()`{.C}.
+
+    ```C
+    #include <stdlib.h>
+    void free(void *ptr);
+    ```
+- 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)
+
+## Tableaux dynamiques
+
+- Pour allouer un espace mémoire de 50 entiers:
+
+    ```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;
+    }
+    ```
+
+## 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)
+
+## Arithmétique de pointeurs
+
+![L'arithmétique des pointeurs.](figs/pointer_arithmetics.svg){#fig:compilation width=100%}
+
+# 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:
+
+    ```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%}
+
+# 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
+    ```
+
+- Ceci est une matrice (un tableau de tableau).
+
+# Prototypes de fonctions (1/N)
+
+## Principes généraux de programmation
+
+- Beaucoup de fonctionnalités dans un code $\Rightarrow$ Modularisation.
+- Modularisation du code $\Rightarrow$ écriture de fonctions.
+- Beaucoup de fonctions $\Rightarrow$ regrouper les fonctions dans des fichiers séparés.
+
+## Mais pourquoi?
+
+- Lisibilité.
+- Raisonnement sur le code.
+- Débogage.
+
+## Exemple
+
+- Libraire `stdio.h`: `printf()`{.C}, `scanf()`{.C}, ...
+
+# Prototypes de fonctions (2/N)
+
+- Prototypes de fonctions nécessaires quand:
+
+    1. Utilisation de fonctions dans des fichiers séparés.
+    2. Utilisation de librairies.
+- Un prototype indique au compilateur la signature d'une fonction.
+- 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)
+
+## Fichier header
+
+- Porte l'extension `.h`
+- Contient: 
+    - définitions des types
+    - prototypes de fonctions
+    - macros
+    - directives préprocesseur (cf. plus loin)
+- Utilisé pour décrire **l'interface** d'une librairie ou d'un module.
+- Un fichier `C` (extension `.c`) utilise un header en *l'important* avec la directive `#include`{.C}:
+
+    ```C
+    #include <stdio.h> // libraire dans LD_LIBRARY_PATH
+    #include "chemin/du/prototypes.h"// chemin explicite
+    ```
+
+# Génération d'un exécutable (1/N)
+
+## 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)
+
+## Un seul fichier source
+
+```bash
+gcc proc.c -o prog
+```
+
+1. **Précompilation: ** `gcc` appelle `cpp`, le préprocesseur qui effectue de la substitution de texte (`#define`, `#include`, macros, ...) et génère le code `C` à compiler, portant l'extension `.i` (`prog.i`).
+2. **Compilation assembleur: ** `gcc` compile le code C en code assembleur, portant l'extension `.s` (`prog.s`).
+3. **Compilation code objet: ** `gcc` appelle `as`, l'assembleur, qui compile le code assembleur en code machine (code objet) portant l'extension `.o` (`prog.o`).
+4. **Édition des liens: ** `gcc` appelle `ld`, l'éditeur de liens, qui lie le code objet avec les librairies et d'autres codes objet pour produire l'exécutable final (`prog`).
+
+Les différents codes intermédiaires sont effacés.
+
+# Génération d'un exécutable (3/N)
+
+## 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)
+
+::: Main
+
+## `main.c`
+
+```C
+#include <stdio.h>
+#include "sum.h"
+int main() {
+  int tab[] = {1, 2, 3, 4};
+  printf("sum: %d\n", sum(tab, 4));
+  return 0;
+}
+```
+:::
+
+:::::::::::::: {.columns}
+
+::: {.column width="45%"}
+
+## `sum.h`
+
+```C
+#ifndef _SUM_H_
+#define _SUM_H_
+
+int sum(int tab[], int n);
+
+#endif
+```
+:::
+::: {.column width="55%"}
+
+## `sum.c`
+
+```C
+#include "sum.h"
+int sum(int tab[], int n) {
+  int s = 0;
+  for (int i = 0; i < n; i++) {
+    s += tab[i];
+  }
+  return s;
+}
+```
+:::
+
+::::::::::::::
+
+
+# Génération d'un exécutable (4/N)
+
+La compilation séparée se fait en plusieurs étapes.
+
+## Compilation séparée
+
+1. Générer séparément les fichiers `.o` avec l'option `-c`.
+2. Éditer les liens avec l'option `-o` pour générer l'exécutable.
+
+## Exemple
+
+- Création des fichiers objets, `main.o` et `sum.o`
+
+    ```bash
+    $ gcc -Wall -Wextra -std=c11 -c main.c
+    $ gcc -Wall -Wextra -std=c11 -c sum.c
+    ```
+- Édition des liens
+
+    ```bash
+    $ gcc main.o sum.o -o prog
+    ```
+
+# Préprocesseur (1/N)
+
+## Généralités
+
+- Première étape de la chaîne de compilation.
+- Géré automatiquement par `gcc` ou `clang`.
+- Lit et interprète certaines directives:
+    1. Les commentaires (`//`{.C} et `/* ... */`{.C}).
+    2. Les commandes commençant par `#`{.C}.
+- Le préprocesseur ne compile rien, mais subtitue uniquement du texte.
+
+## La directive `define`{.C}
+
+- Permet de définir un symbole:
+
+    ```C
+    #define PI 3.14159
+    #define _SUM_H_
+    ```
+- Permet de définir une macro.
+
+    ```C
+    #define NOM_MACRO(arg1, arg2, ...) [code]
+    ```
+
+# Préprocesseur (2/N)
+
+## La directive `include`{.C}
+
+- Permet d'inclure un fichier.
+- Le contenu du fichier est ajouté à l'endroit du `#include`{.C}.
+- Inclusion de fichiers "globaux" ou "locaux"
+
+    ```C
+    #include <file.h>       // LD_LIBRARY_PATH
+    #include "other_file.h" // local path
+    ```
+- Les inclusions multiples peuvent poser problème: définitions multiples. Les headers commencent par:
+
+    ```C
+    #ifndef _VAR_
+    #define _VAR_
+    /*
+    commentaires
+    */
+    #endif
+    ```
+
+
+