// #include // #include // #include // const uint64_t HEAP_SIZE = 32; // const uint64_t BLOCK_SIZE = 8; // uint64_t heap[HEAP_SIZE]; // void init_heap() { // heap[0] = 2; // for (uint64_t i = 1; i + BLOCK_SIZE <= HEAP_SIZE; i += BLOCK_SIZE) { // heap[i] = 0; // } // } // bool is_free(uint64_t i) { return !heap[i - 1]; } // void set_free(uint64_t i) { heap[i - 1] = 0; } // void set_used(uint64_t i) { heap[i - 1] = 1; } // uint64_t *malloc_ui(uint64_t size) { // for (uint64_t i = 2; i - 1 + BLOCK_SIZE <= HEAP_SIZE; i += BLOCK_SIZE) { // if (is_free(i)) { // set_used(i); // if (i > heap[0]) { // heap[0] = i; // } // return &heap[i]; // } // } // return NULL; // } // void free_ui(uint64_t *p) { // uint64_t i = p - heap; // heap[i - 1] = 0; // if (i == heap[0]) { // while (is_free(heap[0]) && heap[0] > 2) { // heap[0] -= BLOCK_SIZE; // } // } // } #include #include #include #include #include // Comme uint64_t est un peu pénible à taper, on utilise // un typedef : typedef uint64_t ui; #define HEAP_SIZE 32 ui heap[HEAP_SIZE]; // Cette fonction convertit un pointeur (qui doit être issu de // malloc_ui) en un indice dans le tableau heap. // Vous en aurez besoin pour écrire les différentes versions // de free_ui (juste un appel au début, ensuite on ne manipule plus // que des indices), mais il est complètement normal de ne pas // comprendre comment elle fonctionne : c'est de l'arithmétique des // pointeurs, qui est hors programme. ui heap_index(ui *p) { return p - heap; } // Cette fonction initialise le tas à une valeur particulière, que // vous avez peu de chance d'utiliser par hasard. Cela nous // permettra en pratique de repérer les cases dont la valeur n'a // jamais été modifiée quand on affiche le contenu du tas. // Elle est destinée à être appelée une unique fois, tout au début // de l'exécution du programme. void pre_initialize_heap(void) { for (ui i = 0; i < HEAP_SIZE; i++) { heap[i] = 0xFFFFFFFF; } } // La fonction suivante affiche le contenu du tas. Les cases // identifiées comme n'ayant jamais été modifiées sont affichées // de manière particulière. void print_heap(void) { for (ui i = 0; i < HEAP_SIZE; i++) { ui x = heap[i]; if (x == 0xFFFFFFFF) { printf("... "); } else { printf("%3" PRIu64 " ", x); } } printf("\n"); } void set_memory(ui *p, ui size, ui value) { for (ui i = 0; i < size; i++) { p[i] = value; } } const ui block_size = 8; void init_heap(void) { heap[0] = 2; for (ui i = 1; i + block_size <= HEAP_SIZE; i += block_size) { heap[i] = 0; } } bool is_free(uint64_t i) { return !heap[i - 1]; } void set_free(uint64_t i) { heap[i - 1] = 0; } void set_used(uint64_t i) { heap[i - 1] = 1; } uint64_t *malloc_ui64(uint64_t size) { for (ui i = 2; i - 1 + block_size <= HEAP_SIZE; i += block_size) { if (is_free(i)) { set_used(i); if (i >= heap[0]) { heap[0] = i + block_size; } return &heap[i]; } } return NULL; } void free_ui64(uint64_t *p) { // Indice du bloc à libérer uint64_t i = heap_index(p); heap[i - 1] = 0; if (i + block_size == heap[0]) { while (heap[0] > 2 && is_free(heap[0] - block_size)) { heap[0] -= block_size; } } } int main(void) { pre_initialize_heap(); // Pour tester, une fois que les fonctions sont implémentées init_heap(); uint64_t *p1 = malloc_ui64(6); uint64_t *p2 = malloc_ui64(3); set_memory(p1, 6, 42); set_memory(p2, 3, 52); print_heap(); uint64_t *p3 = malloc_ui64(5); set_memory(p3, 5, 62); print_heap(); free_ui64(p2); print_heap(); free_ui64(p3); print_heap(); free_ui64(p1); print_heap(); return EXIT_SUCCESS; }