diff --git a/tris_multiples.md b/tris_multiples.md index ebe358538134ecea83dd39275cbdbacedf278efb..b67ac3c8636513ec8a94a68b86aa1b0eeb8d0137 100644 --- a/tris_multiples.md +++ b/tris_multiples.md @@ -47,6 +47,8 @@ Vous aurez plusieurs tâches. ## Remarque +### Le `k`-ème bit d'un entier `n` + Pour le tri par base, vous devez implémenter une fonction qui retourne le `k`-ème bit d'un nombre `n`. Pour ce faire, vous pouvez utiliser la syntaxe suivante: @@ -64,3 +66,88 @@ n >> k == 0011 // 3 en décimal 0011 & 0001 == 0001 // soit 1 en décimale ``` +### L'échange de tableaux statiques + +Certains tris à implémenter, vous devez échanger les pointeurs vers des tableaux statiques. + +Comme plusieurs d'entre-vous l'ont découvert à leur dépens cette étape n'est pas triviale. + +En effet, on pourrait se dire que le code suivant + +```C +int a[] = {1, 2, 3, 4}; +int b[] = {5, 6, 7, 8}; +swap(&a, &b); +// ici en fait a est toujours le tableau 1, 2, 3, 4 +// et b est toujours 5, 6, 7, 8 +``` +ferait pointer le tableau `a` sur les données de `b` et vice-versa. Hors ce n'est absolument pas le cas +car les tableaux statiques **ne sont pas que des pointeurs**. Quand on passe un tableau statique +en argument à une fonction, il est effectivement transformé pointeur. Mais cela ne suffit pas. + +Pour pouvoir effectuer le travail qui vous est demandé, il faut soit faire de l'allocation dynamique +(ce qu'on a pas encore fait en cours) ou alors tricher un peu. En fait, pour réussir à faire un échange +de pointeurs de mémoire, il faut définir deux nouvelles variables, qui sont des vrais pointeurs (elles). +En transformant le code ci-dessus en +```C +int a[] = {1, 2, 3, 4}; +int b[] = {5, 6, 7, 8}; +int *c = a; +int *d = b; +swap(&c, &d); +// ici en fait a est toujours le tableau 1, 2, 3, 4 +// et b est toujours 5, 6, 7, 8 +// mais c pointe sur 5, 6, 7, 8 +// et d pointe sur 1, 2, 3, 4 +``` +on a l'effet voulu. On échange effectivement les pointeurs vers les données voulues. + +### La copie du tableau final + +Quand on échange les pointeurs vers des tableaux statiques dans la fonction de tri, un problème peut survenir. +Prenons le code suivant très simple + +```C +void times_two(int size, int tab[], int tmp[]) { + for (int i = 0; i < size; ++i) { + tmp[i] = 2 * tab[i]; + } +} +void do_things(int size, int tab[]) { + int *tab_ptr = tab; + int tmp[size]; + int *tmp_ptr = tmp; + for (int i = 0; i < 3; ++i) { + times_two(size, tab, tmp) + swap(&tab_ptr, &tmp_ptr); + } +} +int size = 4; +int a[size] = {1, 2, 3, 4}; +do_things(size, a); +``` + +on pourrait se dire que `a` pointerait vers `{8, 16, 24, 32}`. Il n'en est rien. En effet, +dans la fonction `do_things()`, le pointeur `tab` n'est qu'une **copie** du pointeur de `a`. Ainsi, le pointeur vers `a` n'est +jamais vraiment modifié, seul `tab` l'est et il est détruit à la fin de `do_things()`. +Ainsi, comme on échange trois fois le pointeur, on ne modifie qu'une seule fois les données qui sont pointées par `a`, +la valeur contenue dans `a` sera ainsi `{4, 8, 12, 16}`. Pour finir l'implémentation de la fonction, il faut encore copier +les données dans `tab` si le besoin s'en fait sentir (si on allait jusqu'à `4` dans la boucle `for` de `do_things()` +on aurait pas besoin de faire de copie car la dernière modification est dans les données pointées par `a`). + +```C + +void do_things(int size, int tab[]) { + int *tab_ptr = tab; + int tmp[size]; + int *tmp_ptr = tmp; + for (int i = 0; i < 3; ++i) { + times_two(size, tab, tmp) + swap(&tab_ptr, &tmp_ptr); + } + if // trouver la bonne condition + { + copy(size, tmp, tab); // copier les valeur de tmp dans tab + } +} +```