Exercices INGINIOUS¶
Deux sortes d’exercices INGINIOUS vous sont proposés durant cette semaine. Les premiers portent sur les structures chaînées car ces structures de données permettent de bien vérifier la compréhension des pointeurs en C.
- https://inginious.info.ucl.ac.be/course/LSINF1252/simple_stack
- https://inginious.info.ucl.ac.be/course/LSINF1252/cmp_func
- https://inginious.info.ucl.ac.be/course/LSINF1252/linked_structs
- https://inginious.info.ucl.ac.be/course/LSINF1252/advanced_queue
- https://inginious.info.ucl.ac.be/course/LSINF1252/order_relation_linked_list
Après avoir écrit de nombreuses fonctions C, il est maintenant temps pour vous de commencer à écrire des programmes composés de plusieurs fonctions. Pour cela, l’utilitaire make(1) vous sera très utile. Prenez un peu de temps pour lire le chapitre qui lui est consacré dans le syllabus et essayez de répondre aux questions ci-dessous :
Lorsque l’on écrit des programmes en C ou dans un autre langage, il est important de tester le bon fonctionnement de toutes les fonctions du programme pour éviter des erreurs et autres bugs difficiles à corriger. L’idéal est de commencer par écrire les tests qui valident le bon fonctionnement de chaque fonction avant d’écrire cette fonction. Plusieurs librairies peuvent vous aider à écrire de tels tests. CUnit (CUnit: librairie de tests) est l’un d’entre elles. Prenez le temps de lire le chapitre qui lui est consacré dans le syllabus.
Pour démontrer votre bon utilisation de make(1) et CUnit, reprenez le programme que vous avez écrit pour l’exercice test , divisez-le en plusieurs fichiers, ajoutez-y des tests unitaires pour chaque fonction et utilisez make(1) pour automatiser le tout. Si vous voulez allez plus loin, essayez d’utiliser la librarie getopt(3) pour traiter les arguments reçus en ligne de commande.
Verifiez vos réponses¶
Exercices¶
Le principe de localité est un principe très important pour comprendre les performances de programmes qui accèdent beaucoup à la mémoire. Considérons tout d’abord un programme qui doit initialiser une grande zone mémoire obtenue via malloc(3).
- Ecrivez en C une fonction d’initialisation de cette zone mémoire à la valeur
1252
qui profite de la localité spatiale - Ecrivez en C une fonction d’initialisation de cette zone mémoire qui ne profite pas du tout de la localité spatiale
- Comparez les performances des deux programmes que vous avez écrit. Si nécessaire, désactivez l’optimisation du compilateur.
- Ecrivez en C une fonction d’initialisation de cette zone mémoire à la valeur
Un programmeur doit manipuler des tableaux contenant 100.000.000 éléments. Chaque élément du tableau contient un nombre réel et une chaîne contenant 40 caractères. Une opération très courante à effectuer est de calculer la somme de tous les éléments du tableau. A votre avis, quelles seront les performances des deux implémentations suivantes de ce programme :
- Le tableau est implémenté comme un tableau contenant 100.000.000 structures avec dans chaque structure un
float
et unchar c[40]
. - Le tableau est implémenté comme deux tableaux distincts. Le premier contient tous les
float
et le second toutes les chaînes de caractères.
- Le tableau est implémenté comme un tableau contenant 100.000.000 structures avec dans chaque structure un
Un programmeur propose deux fonctions différentes pour calculer la somme des éléments d’un tableau à deux dimensions. Intégrez ces fonctions dans un programme afin d’en mesurer les performances avec gettimeofday(2). Quelle est la variante la plus rapide et pourquoi ?
#define SIZE 10000 int matrix[SIZE][SIZE]; int sum() { int sum=0; for(int i=0;i<SIZE;i++) { for(int j=0;j<SIZE;j++) { sum+=matrix[i][j]; } } return sum; } int sum2() { int sum=0; for(int i=0;i<SIZE;i++) { for(int j=0;j<SIZE;j++) { sum+=matrix[j][i]; } } return sum; }
Question de bilan final¶
Considérez le programme suivant.
#include <stdlib.h> int cours = 1252; int f(int *a, int b) { int c = 97850**a + b; int x = 2052; *a = x * c; return c; } int main(int argc, char *argv[]) { int d = 42; char *tab = malloc(20 * sizeof(char)); int *res = (int *) tab; *tab = f(&cours, d); return 0; }
- Dessinez le schéma de l’organisation mémoire du programme. Identifiez dessus où se trouvent toutes les variables présentes dans le programme.
- Pour chaque ligne du programme, indiquez quelles zones mémoires sont accédées et leur contenu après exécution.