Questions INGINIOUS¶
- Le premier exercice INGINIOUS porte sur le heap et le stack : https://inginious.info.ucl.ac.be/course/LSINF1252/stack_vs_heap
- malloc(3) est une fonction clé en C puisqu’elle permet d’allouer une zone de mémoire. Elle a l’inconvénient de ne pas initialiser cette mémoire, contrairement à calloc(3). Lisez les pages de manuel de ces deux fonctions et implémentez vous-même la fonction calloc(3) en utilisant malloc(3) : https://inginious.info.ucl.ac.be/course/LSINF1252/calloc2
- Lorsque l’on utilise les fonctions de la librairie ou les appels systèmes, il est nécessaire de vérifier chaque fois leur valeur de retour pour éviter tout problème. Dans cet exercice, vous écrivez une variante de malloc(3) qui essaye plusieurs fois d’allouer de la mémoire pour pallier à un problème temporaire de manque de mémoire : https://inginious.info.ucl.ac.be/course/LSINF1252/sleep_malloc
- La question suivante porte sur les déclarations de types de données (faites seulement les 7 premières sous-questions) : https://inginious.info.ucl.ac.be/course/LSINF1252/types
- strcpy(3) est une fonction de la librairie standard qui permet de copier une chaîne de caractères. Cet exercice vous propose d’écrire une variante de cette fonction : https://inginious.info.ucl.ac.be/course/LSINF1252/strcpy
- Lorsque l’on travaille avec les pointeurs, il est possible d’accéder à n’importe quel endroit de la mémoire. Cet exercice vous permet de tester vos compétences de manipulation des pointeurs: https://inginious.info.ucl.ac.be/course/LSINF1252/pointer_types
- Un exercice classique pour montrer que l’on comprend bien les pointeurs est de manipuler des listes chainées: https://inginious.info.ucl.ac.be/course/LSINF1252/basic_linked_list
- Un exercice sur le parcours simple d’un arbre binaire de recherche https://inginious.info.ucl.ac.be/course/LSINF1252/BST
- Un exercice où vous devez analyser l’information reçue d’un modem : https://inginious.info.ucl.ac.be/course/LSINF1252/modem_read
- Maintenant que vous avez écrit de nombreuses fonctions sur INGINIOUS, il est temps pour vous d’écrire votre premier programme directement en C. Utilisez un éditeur de texte pour écrire le fichier
test.c
qui implémente un sous-ensemble du programme standard test(1). Pensez à structurer votre code en utilisant des sous-fonctions. Compilez votre programme sur votre ordinateur avant de le soumettre sur INGINIOUS. https://inginious.info.ucl.ac.be/course/LSINF1252/commandetest
Verifiez vos réponses¶
Questions complémentaires¶
En C, on peut définir des tableaux à deux dimensions avec une déclaration comme
int a[3][3];
. Ecrivez un petit programme qui utilise des pointeurs pour déterminer si un tel tableau à deux dimensions est stocké ligne par ligne ou colonne par colonne.- Exécutez plusieurs fois le code suivant. Expliquez les différents résultats obtenus.
int global; void main(void) { int local; int *ptr1 = (int *)malloc(sizeof(*ptr1)); int *ptr2 = (int *)malloc(sizeof(*ptr2)); printf("global %p loc %p p1 %p p2 %p\n", &global, &local, ptr1, ptr2); }
Un étudiant a fait l’implémentation d’un sous-ensemble des fonctions définies dans string.h, mais il rencontre quelques problèmes avec son code
/Programmes/src/string.c
. Utilisez gdb pour corriger son code. Utilisez le flag-g
degcc
pour ajouter les informations de debug dans votre executable. Pour rappel, voici quelques commandes importantes de gdb:run [ARGS]
permet de lancer l’execution du programme avec les arguments ARGS si spécifiés.break string.c:9
met un point d’arrêt à la ligne 9 du fichier string.cnext
permet d’executer la ligne courante et de s’arrêter à la ligne suivanteprint var
affiche la valeur de la variablevar
backtrace
affiche la pile d’appel des fonctions courantesquit
quitte gdb
Vous travaillez sur un programme qui doit manipuler des vecteurs. Afin de pouvoir supporter des vecteurs de taille quelconque, vous décidez de réimplémenter ces vecteurs vous même en utilisant des pointeurs. Votre programme définit la structure
struct vector_t
et les fonctions ci-dessous. Implémentez ces fonctions sans jamais utiliser la notation des tableaux en C ([
et]
).struct vector_t { int size; float *v; }; // initialise le vecteur à la valeur du réel struct vector_t * init(int, float) ; // récupère le nième élément float get(struct vector_t *, int) ; // fixe la valeur du nième élément void set(struct vector_t *, int , float); // supprime un vecteur void destroy(struct vector_t *);
Expliquez à quoi sert l’attribut
packed
des structures dans gcc(1) (regardez la manpage). Appliquez cet attribut à la structure de l’exercice précédent. Qu’observez-vous comme différence ? Quel sont les avantages et désavantages d’utiliser cet attribut ? Dans quel cas est-il intéressant de l’utiliser ?
Questions de bilan final¶
Lisez attentivement le code suivant et essayez de deviner ce qui sera affiché sur la sortie standard. Ensuite, compilez le code en activant l’option
-fno-stack-protector
de gcc(1) et exécutez le code. Avez-vous bien deviné ? Comment expliquez-vous les lignes affichées par le programme ?#include <stdlib.h> #include <stdio.h> #include <string.h> #include <stdint.h> int f() { uint32_t zero = 0; char a = 'a'; char b = 'b'; char str[8] = "Hello !"; printf("1) str = \"%s\",\t\tzero = %d,\ta = %c,\tb = %c\n", str, zero, a, b); strcpy(str, "I love sour!"); printf("2) str = \"%s\",\tzero = %d,\ta = %c,\tb = %c\n", str, zero, a, b); a = 'a'; b = 'b'; printf("3) str = \"%s\",\tzero = %d,\ta = %c,\tb = %c\n", str, zero, a, b); return 0; } int main(int argc, char *argv[]) { return f(); }
Question ouverte. Soit la structure
pair_t
suivante :typedef struct pair { int a; int b; } pair_t;
Comment feriez-vous pour stocker dans les variables
pair_t *p1, *p2
les pointeurs vers deux instances depair_t
allouées sur le heap de manière contiguë (i.e. les deux structures se suivent directement dans la mémoire) ?