Programmation C
Gestion de la mémoire - Exercices
Cours Exercices Correction des exercices

Exercice 1 Exercice 2 Exercice 3 Exercice 4
Exercice 5 Exercice 6 Exercice 7 Exercice 8

Exercice 1

  • Développer un programme principal réalisant les traitements suivants :
    • Définition d'une variable v de type int initialisée à la valeur 100000000 (100 millions)
    • Affichage du contenu de la variable v
    • Affichage du nombre d'octets occupés par cette variable en mémoire
    • Affichage de l'adresse mémoire de cette variable
    • Définition d'une variable pv1 de type pointeur sur int initialisée à l'adresse de la variable v
    • Affichage du nombre d'octets occupés par cette variable en mémoire
    • Affichage de la valeur de l'int pointé par cette variable
    • Ajout de 1 à l'int pointé par cette variable
    • Nouvel affichage de la valeur de l'int pointé par pv1
    • Définition d'une variable pv2 de type pointeur sur unsigned char (octet en mémoire) initialisée à l'adresse de la variable v1
    • Affichage en hexadécimal et en décimal des valeurs pointées par pv2, pv2+1, pv2+2 et pv2+3 c'est à dire les valeurs des 4 octets mémoires à partir de l'adresse pointée par pv2 incluse
  • Questions
    • Comment retrouve-t-on 100000001 à partir des valeurs des 4 octets ?
    • Que se passe-t-il si on change la valeur de type unsigned char contenue à l'adresse pv2+1 en affectant la valeur 100 à cette adresse ?
      Effectuer la modification dans le programme et afficher la nouvelle valeur de v

Exercice 2

  • Développer un programme principal réalisant les traitements suivants :
    • Calcul et affichage du nombre d'octets nécessaires au stockage de 1000000 de valeurs de type double
    • Définition d'une variable de type pointeur sur double et affectation de cette variable avec le résultat d'exécution de la fonction malloc pour une réservation dynamique de mémoire permettant de stocker 1000000 de valeurs de type double (tableau de 1000000 de double)
    • Affichage du nombre d'octets utilisés en mémoire pour cette variable pointeur, de l'adresse de cette variable et de l'adresse contenue dans cette variable de type pointeur
    • Remplissage du tableau de 1000000 de double avec des valeurs tirées au sort entre 0.0 et 1.0 avec deux chiffres décimaux
    • Calcul et affichage de la moyenne de ce million de valeurs
    • Désallocation du tableau

Exercice 3

  • Développer un programme principal réalisant les traitements suivants :
    • Allocation dynamique d'un tableau de 100000000 de char au moyen d'un calloc
    • Vérification que le nombre de valeurs de ce tableau ayant une valeur différente de 0x00 est égal à 0
    • Désallocation du tableau

Exercice 4

  • Développer un programme principal réalisant les traitements suivants :
    • Allocation d'un tableau de 100 int
    • Affichage de l'adresse de ce tableau
    • Remplissage de ce tableau avec des 1
    • Réallocation de ce tableau pour une taille de 1000 int
    • Affichage de la nouvelle adresse de ce tableau
    • Vérification que le nouveau tableau contient bien les 100 valeurs 1 au 100 premiers indices
    • Désallocation du tableau

Exercice 5

  • Développer une fonction permettant de créer par allocation dynamique et de retourner un tableau de n valeurs de type bool tirées au sort avec équiprobabilité entre true et false
    En cas d'échec de l'allocation, retourner NULL
  • Développer un programme principal réalisant les traitement suivants :
    • Utilisation de la fonction pour allouer un tableau de 500000 bool tirés au sort avec équiprobabilité entre true et false
    • Comptage et affichage du nombre de couples de true consécutifs contenus dans le tableau
    • Désallocation du tableau

Exercice 6

  • La méthode algorithmique permettant de créer par allocation dynamique une matrice telle que proposée en cours fonctionne mais présente des problèmes d'efficacité. Ces problèmes sont liés au fait qu'elle nécessite n+1 allocation dynamiques pour allouer un seul tableau de n lignes.
    • Chaque allocation nécessite l'utilisation d'un peu de mémoire en plus de la mémoire allouée.
    • Chaque allocation consomme une certaine quantité de puissance CPU lors de sa réalisation.
    • Chaque désallocation consomme une certaine quantité de puissance CPU lors de sa réalisation.
    • Le nombre total d'allocations simultanément gérables au sein d'une application et au sein du système d'exploitation est grand mais possède une limite.
    • ...
  • Le but étant bien entendu de toujours obtenir un pointeur sur pointeur sur type, il est possible d'opérer autrement en ne faisant que deux allocations dynamiques pour réserver une matrice de nbL x nbC valeurs de type type. Plutôt que de disséminer en mémoire les zones contenant chaque ligne de valeurs (zones repérées par l'adresse de leur première valeur), une seule zone est réservée avec une taille suffisante pour tout stocker. On extrait ensuite l'adresse affectée à chaque ligne en calculant l'adresse des valeurs d'indice i*nbC de la zone globale allouée extrayant ainsi nbL bancs consécutifs de nbC valeurs au sein de la zone de nbL*nbC valeurs. Pour la désallocation, seules deux libérations ont à être réalisées car seules deux allocations ont été réalisées.
  • Les opérations à réaliser pour l'allocation d'une matrice sont
    • Définir une variable mat de type pointeur sur pointeur sur type
    • Faire une allocation dynamique pour nbL valeurs de type pointeur sur type et stocker le résultat dans la variable mat
    • Faire une allocation dynamique pour nbL*nbC valeurs de type type et stocker le résultat dans mat[0]
    • Affecter à tous les mat[i] restants (i de 1 à nbL-1) l'adresse de mat[0][i*nbC]
  • Les opérations à réaliser pour la désallocation d'une matrice mat sont
    • Libérer mat[0]
    • Libérer mat
  • Développer selon la technique proposée ci-avant
    • une fonction de création par allocation dynamique d'une matrice d'int
      • intégralement initialisée à 0
      • de nbL lignes et de nbC colonnes
      • de signature int** creerMatrice(size_t nbL,size_t nbC);
      • de retour NULL en cas d'échec de l'allocation dynamique
    • une fonction de désallocation d'une matrice d'int de signature void detruireMatrice(int** mat);
  • Vérifier le bon fonctionnement de ces deux fonctions en les testant sur le programme principal suivant (compléter là où se trouvent les points de suspension) :

#include <stdio.h>
#include <stdlib.h>

int** creerMatrice(size_t nbL, size_t nbC) {
  ...
}

void detruireMatrice(int** mat) {
  ...
}

long long calculerNombreOccurrences(int** mat, size_t nbL, size_t nbC, int v) {
  long long cpt = 0;
  if (mat != NULL) {
    for (int l = 0; l < nbL; l++) {
      for (int c = 0; c < nbC; c++) {
        if (mat[l][c] == v) {
          cpt++;
        }
      }
    }
  }
  return cpt;
}

void initialiser(int** mat, size_t nbL, size_t nbC, int v) {
  if (mat != NULL) {
    for (int l = 0; l < nbL; l++) {
      for (int c = 0; c < nbC; c++) {
        mat[l][c] = v;
      }
    }
  }
}

int main(void) {
  int** m1 = creerMatrice(1, 1);
  printf("m1 : %p\n", m1);
  initialiser(m1, 1, 1, 10);
  printf("Nombre de valeurs egales a 10 : %lld\n", calculerNombreOccurrences(m1, 1, 1, 10));
  printf("\n");
  detruireMatrice(m1);
  size_t nbC = 5000000;
  printf("Nombre de colonnes : %zu\n", nbC);
  m1 = NULL;
  for (int i = 1; i <= 25; i++) {
    size_t nbL = i * 200;
    int** m = creerMatrice(nbL, nbC);
    printf("Matrice de %4zu lignes : %20p\n", nbL, m);
    initialiser(m, nbL, nbC, i);
    printf("Nombre de valeurs      : %20lld\n", calculerNombreOccurrences(m, nbL, nbC, i));
    detruireMatrice(m);
    m = NULL;
  }
  return 0;
}

06-Exercice6-Base.c - 06-Exercice6-Base.exe
  • Etape 1
    • Création d'une matrice de taille 1x1
    • Affectation de son unique valeur avec la valeur 10
    • Comptage du nombre de 10 contenus par la matrice et affichage du nombre obtenu
    • Destruction de la matrice
  • Etape 2
    • Créations successives de 25 matrices de tailles croissantes (nombre de lignes égal 200, 400, 600, ..., 5000, nombre de colonnes égal 5000000)
    • Pour chacune des 25 matrices
      • Affectation intégrale de ses valeurs avec la valeur n = nombre de lignes / 200 (1 pour 200, 2 pour 400, 3 pour 600, ..., 25 pour 5000) c'est à dire une valeur différente pour chaque matrice
      • Comptage du nombre de valeurs n contenues par la matrice et affichage du nombre obtenu
      • Destruction de la matrice
  • Opérations réalisées sur les matrices : création, parcour complet en écriture et en lecture, et destruction.
  • Sauf si beaucoup de mémoire disponible, créations de matrice en échec avant la fin d'exécution du programme, mais sans plantage si fonctions de création et destruction bien conçues
  • Résultat d'exécution variable suivant les ordinateurs car dépendant de la mémoire disponible sur l'ordinateur
  • Diminuer le nombre de colonnes (5000000 dans le programme) si même la création d'une matrice de 200 lignes est impossible
m1 : 000001755F41BC60
Nombre de valeurs egales a 10 : 1

Nombre de colonnes : 5000000
Matrice de  200 lignes :     000001755F420EE0
Nombre de valeurs :                1000000000
Matrice de  400 lignes :     000001755F422FE0
Nombre de valeurs :                2000000000
Matrice de  600 lignes :     000001755F422FE0
Nombre de valeurs :                3000000000
Matrice de  800 lignes :     000001755F422FE0
Nombre de valeurs :                4000000000
Matrice de 1000 lignes :     000001755F422FE0
Nombre de valeurs :                5000000000
Matrice de 1200 lignes :     000001755F422FE0
Nombre de valeurs :                6000000000
Matrice de 1400 lignes :     000001755F422FE0
Nombre de valeurs :                7000000000
Matrice de 1600 lignes :     000001755F422FE0
Nombre de valeurs :                8000000000
Matrice de 1800 lignes :     000001755F422FE0
Nombre de valeurs :                9000000000
Matrice de 2000 lignes :     000001755F422FE0
Nombre de valeurs :               10000000000
Matrice de 2200 lignes :     000001755F422FE0
Nombre de valeurs :               11000000000
Matrice de 2400 lignes :     000001755F422FE0
Nombre de valeurs :               12000000000
Matrice de 2600 lignes :     000001755F422FE0
Nombre de valeurs :               13000000000
Matrice de 2800 lignes :     000001755F422FE0
Nombre de valeurs :               14000000000
Matrice de 3000 lignes :     000001755F422FE0
Nombre de valeurs :               15000000000
Matrice de 3200 lignes :     000001755F422FE0
Nombre de valeurs :               16000000000
Matrice de 3400 lignes :     000001755F422FE0
Nombre de valeurs :               17000000000
Matrice de 3600 lignes :     000001755F422FE0
Nombre de valeurs :               18000000000
Matrice de 3800 lignes :     000001755F422FE0
Nombre de valeurs :               19000000000
Matrice de 4000 lignes :     000001755F422FE0
Nombre de valeurs :               20000000000
Matrice de 4200 lignes :     000001755F422FE0
Nombre de valeurs :               21000000000
Matrice de 4400 lignes :     0000000000000000
Nombre de valeurs :                         0
Matrice de 4600 lignes :     0000000000000000
Nombre de valeurs :                         0
Matrice de 4800 lignes :     0000000000000000
Nombre de valeurs :                         0
Matrice de 5000 lignes :     0000000000000000
Nombre de valeurs :                         0

Exercice 7

  • Développer une fonction de création d'une copie d'une chaîne de caractères avec allocation dynamique de la chaîne résultat
  • Valider

Exercice 8

  • On souhaite calculer le triangle de Pascal de hauteur n (avec n > 1). Ce triangle est constitué de n lignes de valeurs entières avec 1 valeur à la première ligne, 2 valeurs à la deuxième ligne, 3 valeurs à la troisième ligne, ..., n valeurs à la nième ligne. La 1ère colonne et la diagonale du triangle contiennent des 1. Pour calculer la valeur d'indice (i,j), on somme des deux valeurs d'indices (i-1,j-1) et (i-1,j) (valeurs préalablement calculées bien entendu). Pour n = 10 on obtient donc
    1                  
    1 1                
    1 2 1              
    1 3 3 1            
    1 4 6 4 1          
    1 5 10 10 5 1        
    1 6 15 20 15 6 1      
    1 7 21 35 35 21 7 1    
    1 8 28 56 70 56 28 8 1  
    1 9 36 84 126 126 84 36 9 1
  • Développer une fonction permettant d'allouer en mémoire une "matrice" de n lignes de long long caractérisée par le fait que le nombre de valeurs stockables sur chaque ligne augmente de 1 à chaque ligne avec 1 valeur sur la première ligne
  • Développer une fonction permettant de désallouer une matrice telle que celle allouée à la question précédente
  • Développer une fonction permettant de créer entièrement un triangle de Pascal de taille n.
  • Valider