Inf3135 Examen Final
Inf3135 Examen Final
Inf3135 Examen Final
Identification :
Nom,
prénom :
Code
permanent :
Note : /100
Directives :
a) (5 points) La performance bien qu'étant est un aspect important, n'est pas l'objectif
premier du logiciel ?
Quels objectifs viennent avant la performance dans le développement d'un logiciel ?
Justifiez votre réponse.
Le temps machine d’exécution ne dépend pas de la complexité de l’algorithme mais plutôt des
ressources matérielles de l’ordinateur et de son contexte d’exécution (processeur disponible,
quantité de mémoire, etc.).
Quand optimiser ?
Lorsque le choix des algorithmes et des structures de données n’est pas en cause.
Lorsque le programme est utilisé souvent et résous un problème important.
Lorsque le programme est réellement trop lent ou utilise trop de ressources.
Quoi ?
Algorithme utilise
Comment ?
En enlevant les opérations inutiles
Simplifiant les calculs
Utilisant plus efficacement la mémoire
a) (5 points) Une des façons de mettre en place des tests fonctionnels en C est de se servir
d’un shell-script. Le shell-script est un fichier texte qui contient des commandes shell.
Supposons un logiciel, qui prend un ensemble de données en entrée et qui produit un
certain résultat en sortie. Décrivez les différentes étapes nécessaires à la mise place
de test fonctionnel à travers un shell-script.
Maintenance perfective :
Maintenance corrective :
Ces changements sont effectués pour réparer des défauts du système tels que :
o erreurs de conception
Maintenance adaptative
Maintenance préventive
Ces changements ont pour but de prévenir la détérioration du logiciel face aux
changements futurs
c) (5 points) Quelles sont les étapes à suivre lors d’une activité de maintenance ?
Dans cette question, vous devez compléter l’implémentation d’une liste circulaire.
Une liste circulaire est essentiellement d’une liste doublement chaînée ayant la propriété
additionnelle que le premier et le dernier noeud sont reliés comme s’ils étaient consécutifs.
Voici une représentation schématique d’une liste circulaire contenant dans l’ordre les
caractères ’G’, ’A’, ’T’, ’T’, ’A’, ’C’ et ’A’ :
Dans la figure qui ci-dessus, les flèches pleines correspondent aux pointeurs next (noeud
suivant), alors que les flèches pointillées correspondent aux pointeurs prev (noeud
précédent).
Un curseur d’une liste circulaire est simplement un pointeur vers un des noeuds. Dans
l’exemple ci-dessus, on pourrait avoir par exemple un curseur qui pointe vers le noeud le plus
à gauche de la liste circulaire :
Prenez le temps de bien lire toutes les déclarations, incluant la documentation (docstring)
expliquant le comportement attendu de chaque fonction :
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// ----- //
// Types //
// ----- //
/**
* Une liste circulaire est exactement comme une liste doublement chaînée, à l'exception
* les premier et dernier nœuds sont également liés, faisant une boucle.
*/
struct CircularList { // La liste circulaire
struct Node *cursor; // Le nœud courant
unsigned int num_elements; // Le nombre
d’éléments
};
// //
// Fonctions //
// //
/**
* Crée une liste circulaire
*
* Note: N'oubliez pas d'utiliser ‘circular_delete‘ lorsque vous avez terminé.
*
* @return La liste circulaire
* /
struct CircularList circular_create() {
struct CircularList cl;
cl.cursor = NULL;
cl.num_elements = 0;
return cl;
}
/**
* Renvoie vrai si et seulement si une liste circulaire est vide
*
* @param cl La liste circulaire
* @return True si la liste est vide, false sinon
*/
bool circular_is_empty(const struct CircularList *cl) {
// TODO 1 //
}
/**
* Imprime les `n` premiers éléments d'une liste circulaire sur `stdout`,
* à partir du nœud courant (cursor)
*
* Puisque la liste est circulaire, `n` peut être plus grand que le nombre d'éléments dans
* la liste, et les éléments sont simplement répétés autant de fois que nécessaire.
*
* Si la liste est vide, alors elle affiche "( )", quelle que soit la valeur de `n`.
*
* @param cl Un pointeur vers une liste circulaire
* @param n Le nombre d'éléments à imprimer
* @param forward Si vrai, la liste est imprimée en avant
* sinon, il est imprimé à l'envers
*/
void circular_print(const struct CircularList *cl,
unsigned int n,
bool forward) {
// TODO 2 //
}
/**
* Insère une valeur dans une liste circulaire
*
* @param cl La liste circulaire
* @param value La valeur à insérer
*/
void circular_insert(struct CircularList *cl, char value) {
struct Node *node = malloc(sizeof(struct Node));
node->value = value;
if (circular_is_empty(cl)) {
node->next = node;
node->prev = node;
} else {
node->next = cl->cursor;
node->prev = cl->cursor->prev;
cl->cursor->prev = node;
if (cl->cursor->next == cl->cursor) {
cl->cursor->next = node;
}
node->prev->next = node;
}
cl->cursor = node;
++cl->num_elements;
}
/**
* Pop la valeur actuelle (au curseur) à partir d'une liste circulaire
*
* En d'autres termes, il supprime le nœud pointé par le curseur de la liste
* circulaire et renvoie le caractère qu'il contient.
*
* Remarque : si la liste est vide, le caractère '?' est renvoyé et une erreur est
* imprimé sur stderr.
*
* @param cl La liste circulaire
* @return Le caractère stocké au nœud pointé par le curseur
*/
char circular_pop(struct CircularList *cl) {
// TODO 3 //
}
/**
* Déplace le curseur d'une liste circulaire de `i` éléments.
*
* Si la liste est vide, rien ne se passe.
* Si `i > 0`, alors le curseur est déplacé de `i` éléments vers l'avant (direction
* next).
* Si `i < 0`, alors le curseur est déplacé de `-i` éléments vers l'arrière (direction
* prev).
*
* @param cl La liste circulaire
* @param i La valeur du décalage
*/
void circular_shift(struct CircularList *cl, int i) {
// TODO 4 //
}
/**
* Supprime une liste circulaire
*
* @param cl La liste circulaire
*/
void circular_delete(struct CircularList *cl) {
while (!circular_is_empty(cl)) {
circular_pop(cl);
}
}
Complétez dans les boîtes ci-bas l’implémentation des trois fonctions suivantes :
a) (5 points) bool circular_is_empty(const struct CircularList *cl)
// TODO 1 //
return cl->cursor == NULL;
// TODO 2 //
if (circular_is_empty(cl) ) {
printf("( )");
} else {
printf("(");
if (forward) {
ptr = ptr->next;
} else {
ptr = ptr->prev;
}
}
printf(")");
}
// TODO 3 //
if (circular_is_empty(cl) ) {
fprintf( stderr, "erreur : liste vide\n");
return '?';
} else {
struct Node *ptr = cl->cursor;
cl->cursor = ptr->next;
cl->cursor->prev = ptr->prev;
ptr->prev->next = cl->cursor;
++cl->num_elements;
return ptr->value;
}
// TODO 4 //
if (!circular_is_empty(cl) ) {
struct Node *ptr = cl->cursor;
int a, b = i < 0 ? -i : i;
for (a = 0; a < b; a++) {
if (i > 0) {
ptr = ptr->next;
} else if (i < 0){
ptr = ptr->prev;
}
}
cl->cursor = ptr;
}
build : test.c
gcc test.c -std=C11 -o test
leak: build
valgrind --leak-check=yes ./test
release: test.c
gcc test.c -std=C11 -NDEBUG -o test-release
debug: test.c
gdb -g test.c
gdb ./test
Depuis quelques jours, une nouvelle application de réseaux sociaux, appelée Bookcafé, a fait
son apparition. Par un pur hasard, on vous a donné accès au code source, disponible en
annexe. Prenez le temps de bien le lire, ainsi que sa documentation.
L’objectif de cette question est d’effectuer différentes activités de maintenance sur ce logiciel
futuriste afin de
l’améliorer.
// On cherche la position
int pos = 0;
while (pos < network -> num_element && bookcafe_compare_people(person, network ->
people[pos]){
pos++;
}
// On ajoute l'élément à sa positopn en décalant le reste
struct Node node* = NULL;
while (pos < num_element){
tnode = network -> people[pos];
network -> peope[pos] = person;
pos++;
person = network -> people[pos];
}
ii. (10 points) La fonction bookcafe_add_person ne vérifie pas si on ajoute une personne
dont le courriel est déjà utilisé dans le réseau social. Autrement dit, on peut avoir
deux personnes dans le réseau qui utilisent la même adresse courriel, ce qui n’est pas
souhaitable. En utilisant la stratégie de votre choix basée sur la programmation
défensive, rectifiez cette situation. Justifiez votre réponse.
Mettre tout le code dans un IF qui verifie si la personne n'est pas déjà contenue dans la liste
en utilisant la fonction "bookcafe_has_person" :
If ( !bookcafe_has_person(c1,person){
…
}
Si on appelle la fonction avec une adresse "email1" qui correspond à une personne
qui n'existe pas dans le q réseau. Le pointeur "person1" sera initialisé avec un NULL et
passer en paramètre à "bookcafe_add_relation_to_person" qui crea une erreur de
segmentation
(3) (5 points) Décrivez toutes les préconditions et postconditions pertinentes pour la fonction
bookcafe_add_relationship. Ensuite, ajoutez des assertions qui permettent non
seulement de résoudre le problème mentionné à la sous-question (2), mais également
tout autre problème potentiel qui pourrait survenir dans cette fonction.
- preconditions:
- les varriables Person ne sont pas nulles
- le network a une taille minimale de 2
- postcondition
- les relations sont écrites en mémoire
- les assertions:
- A la ligne 214:
ASSERT_NOT_NULL(person1);
ASSERT_NOT_NULL(person2);
- A la ligne 215:
ASSERT_EQUAL(bookcafe_compare_people(person1->relations->with, person2);
ASSERT_EQUAL(bookcafe_compare_people(person1->relations->type, type);
- A la ligne 217:
ASSERT_EQUAL(bookcafe_compare_people(person2->relations->with, person1);
ASSERT_EQUAL(bookcafe_compare_people(person2->relations->type, type);