Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Inf3135 Examen Final

Télécharger au format docx, pdf ou txt
Télécharger au format docx, pdf ou txt
Vous êtes sur la page 1sur 22

UQAM – Département Informatique Examen final – Automne 2022

INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

Examen final : INF3135 - Automne


2022

Identification :

Nom,

prénom :

Code

permanent :

Note : /100

Directives :

 Identifiez votre feuille de réponses (pénalité 20 points).


 Placez votre carte étudiante de l'UQAM, sur le bureau. Présentez la carte au
surveillant lors de la remise de votre copie.
 Une feuille de note manuscrite format lettre (recto-verso) est permise.
 Fermez votre sonnerie de téléphone et rangez-le dans votre sac déposé au sol.
Un contact avec votre téléphone ou tout autre dispositif électronique durant
l'examen entraînera une expulsion.
 Vous n'êtes pas tenu d'utiliser tout l’espace de réponse mise à votre disposition. Par
contre, votre
réponse ne doit pas dépasser l’espace prévu.
 Toute réponse illisible ne sera pas évaluée.

 2022 - Serge Dogny 1/20


UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

Question 1 : (15 points)

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.

Qualité fonctionnelle du programme


- Conforme aux spécifications
- Absence de bogues ou dysfonctionnements
- Qualité du code
- Maintenable
- Découpage modulaire approprié

b) (5 points) La complexité asymptotique est la mesure du temps (complexité temporelle)


et de l'espace (complexité spatial) nécessaire à un algorithme lors de son exécution.
Expliquez pourquoi la complexité temporelle est plutôt représentée par le nombre
d'opérations (addition, comparaison, ...) requises et non le temps machine.

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.).

 2022 - Serge Dogny 2/20


UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

c) (5 points) Quand, quoi et comment optimiser ?

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

 2022 - Serge Dogny 3/20


UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

Question 2 : (15 points)

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.

1. On place les entrées dans un fichier


2. On place le résultat a8endu dans un fichier
3. On exécute le programme en redirigeant stdin sur le fichier d'entrée et stdout sur un
fichier temporaire
4. On compare le fichier temporaire avec le résultat attendu

b) (5 points) Il existe 4 types de maintenance regroupés en 2 catégories : La maintenance


proactive et réactive. Citez et définissez avec un exemple à l’appui, les types de
maintenance qui composent d’une part la maintenance proactive et d’autre part la
maintenance réactive.

Maintenance proactive = maintenance préventive et maintenance perfective.

Maintenance réactive = maintenance corrective et maintenance adaptative.

Maintenance perfective :

Ces changements ont pour but d'améliorer le produit, tels que :

o l'ajout de nouvelles exigences de l'utilisateur ou

o l'amélioration des performances, de la convivialité etc.

Maintenance corrective :

Ces changements sont effectués pour réparer des défauts du système tels que :

o erreurs de conception

o erreurs de programmation, logique, etc.

o Toute correction d’erreur logicielle (bogue) est de la maintenance corrective

Maintenance adaptative

Ces changements sont apportés pour suivre le rythme du changement des


environnements tels que

 2022 - Serge Dogny 4/20


UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

o les nouveaux systèmes d’exploitation, les compilateurs,

o les nouveaux langages et Framework,

o les systèmes de gestion de base de données, etc.

o C’est un ajustement au logiciel et non pas un correctif

Maintenance préventive

Ces changements ont pour but de prévenir la détérioration du logiciel face aux
changements futurs

o d'améliorer la «maintenabilité» et l’habilité future du système.

o Contrairement aux précédentes raisons de changements réactives, les changements


préventifs cherchent de manière proactive de simplifier l’évolution future du système.

 2022 - Serge Dogny 5/20


UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

c) (5 points) Quelles sont les étapes à suivre lors d’une activité de maintenance ?

Avant de modifier le système :

1. On doit comprendre le logiciel, au niveau fonctionnel et structurel


2. Comprendre les modifications demandées
3. Évaluer de quelles façons ces modifications peut être apportées
4. Si possible, proposer une ou plusieurs approches de mise en œuvre des modifications
demandées
5. Évaluer l’impact de la réalisation de ces modifications :
o Les structures de données sont-elles affectées ?
o Quelles sections de code sont touchées ?
6. Choisir la solution la moins coûteuse, la moins complexe et la plus facile à maintenir à
long terme
7. L’implémenter en respectant le plus possible le style de programmation
8. Mettre à jour les plans de tests ou en ajouter si inexistants
9. Vérifier que le nouveau programme passe les tests
10. Documenter les modifications apportées, en particulier, décrire le problème et la solution
apportée
11. Si nécessaire, donner une formation aux utilisateurs sur les nouvelles fonctionnalités
12. Coordonner la mise en production

 2022 - Serge Dogny 6/20


UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

Question 3 : (30 points)

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’ :

Un noeud d’une telle liste est représenté grâce à la déclaration suivante :

struct Node { // Un nœud dans une liste circulaire


char value; // la valeur
struct Node *prev; // Le nœud précédent
struct Node *next; // Le nœud suivant
};

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 :

 2022 - Serge Dogny 7/20


UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

Voici son implémentation : le fichier circular.c :

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

// ----- //
// Types //
// ----- //

struct Node { // Un nœud dans une liste circulaire


char value; // la valeur
struct Node *prev; // Le nœud précédent
struct Node *next; // Le nœud suivant
};

/**
* 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 //
}

 2022 - Serge Dogny 8/20


UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

/**
* 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;
}

 2022 - Serge Dogny 9/20


UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

/**
* 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);
}
}

 2022 - Serge Dogny 10/


20
UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

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;

b) (10 points) void circular_print(const struct CircularList *cl,


unsigned int n, bool forward )

// TODO 2 //
if (circular_is_empty(cl) ) {
printf("( )");
} else {

printf("(");

struct Node *ptr = cl->cursor;


int I;

for (i =0; i < n; i++) {


printf("%c",ptr->value);

if (forward) {
ptr = ptr->next;
} else {
ptr = ptr->prev;
}
}
printf(")");
}

 2022 - Serge Dogny 11/


20
UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

c) (10 points) char circular_pop(struct CircularList *cl)

// 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;
}

d) (5 points) void circular_shift(struct CircularList *cl, int i)

// 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;
}

 2022 - Serge Dogny 12/


20
UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

Question 4 : (10 points)


Considérez le fichier test.c suivant :

Proposez un Makefile minimal et complet respectant les critères suivants :


 Le nom de l’exécutable doit être test et le standard utiliser doit être spécifiée
 La commande make leak doit lancer une commande qui permet de détecter les fuites
de mémoire
 La commande make release doit produire un exécutable nommé test-release en
désactivant les assertions et en n’incluant pas les instructions de débogage
 En particulier, l’exécutable test-release ne doit pas être généré à nouveau s’il est à
jour.
 La commande make debug doit lancer le débogueur gdb sur l’exécutable.

NB : N’utilisez pas de variables et exprimez bien toutes les dépendances pertinentes

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

 2022 - Serge Dogny 13/


20
UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

Question 5 : (30 points)

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.

(1) Modifiez la fonction bookcafe_add_person en tenant compte des deux observations


suivantes :

i. (10 points) La fonction bookcafe_add_person est inefficace. En effet, chaque fois


qu’on y insère une nouvelle personne, elle trie le tableau complet, ce qui peut prendre
un temps de O(n2) dans le pire cas, où n est le nombre de personnes dans le réseau.
Proposez une implémentation alternative plus efficace qui prend un temps dans O(n).
Justifiez votre réponse.

// 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];
}

 2022 - Serge Dogny 14/


20
UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

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){

}

 2022 - Serge Dogny 15/


20
UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

(2) (5 points) Donnez un exemple d’appel de la fonction bookcafe_add_relationship qui


déclenchera une erreur de segmentation lorsque le programme parcourra la fonction
bookcafe_add_relation_to_person. Justifiez votre réponse

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

 2022 - Serge Dogny 16/


20
UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

 2022 - Serge Dogny 17/


20
UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

(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);

 2022 - Serge Dogny 18/


20
UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

Annexe A : Fichier bookcafe.c

 2022 - Serge Dogny 19/


20
UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

 2022 - Serge Dogny 20/


20
UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

 2022 - Serge Dogny 21/


20
UQAM – Département Informatique Examen final – Automne 2022
INF 3135 - Groupes 20 & 40 2022-12-17 ( 14h00 - 17h 00)

 2022 - Serge Dogny 22/


20

Vous aimerez peut-être aussi