Lab #1 - Introduction à la programmation C
Objectifs
- Mettre à jour son environnement de travail
- Savoir compiler/exécuter un programme C
- Connaître la syntaxe de base du langage C et
- variables, types primitifs
- savoir utiliser les structures de contrôle classique
- boucles, conditionnelles, etc.
- Définitions et appels de fonctions
- Définition, initialisation et utilisations de tableaux à taille fixe
- Gestion élémentaire des entrées/sorties
- Programmation modulaire et compilation séparée
- écriture d'un
makefile
et utilisation de la commandemake
- écriture d'un
Préliminaires
Vous réaliserez ce travail dans un dépôt Git local. Il vous est demandé de commiter régulièrement vos contributions et de pousser celles-ci sur la plateforme GitLab (https://gitlab.telecomnancy.univ-lorraine.fr) de l'école. Veillez à organiser votre dépôt de la manière suivante :
- un répertoire
src/
dans lequel vous placerez le code source de votre travail - ne committez que le code source
.c
et non les versions compilées de vos programme. Pour cela ajouter le nécessaire dans le fichier.gitignore
pour ignorer les fichiers.o
notamment.
Rendu
Ce travail est à rendre au plus tard le lundi 4 avril 2022 à 13:00 sur la plateforme GitLab de l'école.
Pré-requis
Pour l'ensemble du module, nous utiliserons l'environnement de développement intégré Visual Studio Code (https://code.visualstudio.com/). Cet environnement est normalement déjà installé dans la machine virtuelle.
Sinon, vous devrez :
- Téléchargez et installez celui-ci si ce n'est pas déjà fait (https://code.visualstudio.com/).
Vous devez maintenant, si ce n'est pas déjà fait, cloner le dépôt du TP, vous placer dans le répertoire ainsi créer. Plus tard, vous devrez ouvrir ce répertoire dans Visual Studio Code (en utilisant la commande code .
par exemple).
# en SSH
git clone git@gitlab.telecomnancy.univ-lorraine.fr:c2k22/lab1-oster7.git
# ou en HTTPS (ici on insére l'adresse email dans l'URL lors du "clonage" afin de ne pas avoir à la re-saisir plus tard -- à chaque "push")
git clone https://gerald.oster%40telecomnancy.eu@gitlab.telecomnancy.univ-lorraine.fr/c2k22/lab1-oster7.git
cd lab1-oster7.git
C'est parti !
Environnement de développement
Cette section est dédiée à la configuration de votre environnement de développement. Les explications sont dédiées à être réalisée sur la machine virtuelle (VirtualBox) fournie par l'école. Elles peuvent être facilement adaptées pour un autre environnement GNU/Linux ou pour macOS.
Cette année, dans le module de C, nous utiliserons exclusivement le compilateur Clang (https://clang.llvm.org/) et l'environnement de développement intégré Visual Studio Code (https://code.visualstudio.com/).
Première partie : Mise à jour de votre environnement
Dans cette partie, nous allons voir comment mettre à jour votre environnement de travail est plus précisément comment étendre l'espace disque de votre machine virtuelle Telecom Nancy, faire un peu de nettoyage, mettre à jour votre environnement et installer les outils nécessaires à la suite du module.
Ajouter de l'espace de stockage à votre machine virtuelle
Cette sous-section est optionnelle, si vous avez suffisamment d'espace disque dans votre machine virtuelle
Si vous disposez de suffisamment d'espace sur votre machine physique alors vous pouvez dédier un peu plus d'espace disque à votre machine virtuelle (l'espace prévu initialement étant un peu trop restreint).
- Exécutez VirtualBox, mais ne démarrez par la machine virtuelle
- Sélectionner sur la machine virtuelle -> Configuration -> Stockage -> Contrôleur SATA -> Ajouter un nouveau disque dur
- Créer -> VDI (VirtualBox Disk Image) -> Taille fixe -> Indiquer un chemin (celui par défaut devrait convenir) et la taille (10 Go devrait convenir) -> Créer
- Démarrer votre machine virtuelle
- Exécuter les commandes suivantes dans un terminal :
# affiche l'espace dispnonible et total
df -h /
# crée un nouveau volume physique LVM à partir du nouveau disque ajouté
sudo pvcreate /dev/sdb
# ajoute le nouveau volum physique au groupe de volume
sudo vgextend vgubuntu /dev/sdb
# étend l'espace logique en utilisant 100% de l'espace disponible dans le volume logique
sudo lvextend -l +100%FREE /dev/vgubuntu/root
# redimensionne l'espace de fichiers ext4
sudo resize2fs /dev/vgubuntu/root
# affiche à nouveau l'espace dispnonible (qui a dû augmenté)
df -h /
Faire un peu de place dans la machine virtuelle (VM)
sudo snap set system refresh.retain=2 # pour limiter le nombre de version conservée en archive
LANG=c snap list --all | while read snapname ver rev trk pub notes; do if [[ $notes = *disabled* ]]; then sudo snap remove "$snapname" --purge --revision=$rev; fi; done # pour supprimer toutes les versions qui ne sont pas actives
Pour désinstaller IntelliJ et PyCharm si vous ne vous en servez pas (si vous ne les utilisez pas -- nous ne les utiliserons pas en TP)
sudo snap remove --purge intellij-idea-ultimate
sudo snap remove --purge pycharm-professional
Mettre à jour les paquets installés sur la VM
sudo apt-get update
sudo apt-get upgrade
Redémarrage de la machine virtuelle
reboot
Suppression de CLang v10 et installation de la version v12
sudo apt-get install clang-12
sudo apt-get remove clang-10
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-12 120 --slave /usr/bin/clang++ clang++ /usr/bin/clang++-12
Vous pouvez vérifier votre version de clang est utilisant la commande suivante :
clang --version
Vous devriez avoir un affichage équivalent à celui présenté ci-dessous :
Ubuntu clang version 12.0.0-3ubuntu1~20.04.5
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Suppression des paquets "temporaires" et "archivés"
sudo apt-get clean
sudo apt-get autoremove
Deuxième partie : Configuration de Visual Studio Code
Dans cette section, vous trouverez les deux extensions à installer
ms-vscode.cpptools-extension-pack
C/C++ Extension pack https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools-extension-pack
Sources:
- https://code.visualstudio.com/docs/cpp/config-linux
- https://code.visualstudio.com/docs/cpp/config-clang-mac
Dans un terminal, vous pouvez simplement exécuter la commande suivante :
code --install-extension ms-vscode.cpptools-extension-pack
ms-vscode.makefile-tools
Makefile Tools https://marketplace.visualstudio.com/items?itemName=ms-vscode.makefile-tools
Sources:
Dans un terminal, vous pouvez simplement exécuter la commande suivante :
code --install-extension ms-vscode.makefile-tools
Validation
Une fois que vous avez réalisé toutes les étapes précédentes, exécuter le script report.sh
.
./report.sh
Exercices
Ouvrez dans Visual Studio Code le répertoire de votre dépôt. Vous pouvez par exemple utiliser la commande suivante :
cd lab1-oster7 # si ce n'est déjà fait
code . # pour ouvrir (en tant que projet) le répertoire courant
Exercice 1 : Hello world
-
Dans un fichier
helloworld.c
, écrivez un programme permettant d'afficher le messageHello, World!
sur la sortie standard.Si vous avez besoin d'aide concernant une fonction de la librairie C, nous vous invitons à consulter la page
man
dédiée à cette fonction (i.e. pour obtenir la documentation de la fonctionprintf
vous pouvez utiliser la commandeman 3 printf
). -
Compilez et exécutez ce programme.
Pour rappel, les lignes de commande à utiliser sont (si vous avez des questions à ce sujet, n'hésitez pas à interpeller votre chargé(e) de TD/TP) :
clang -c -Wall -Wextra -pedantic -O0 -g3 -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls helloworld.c clang -Wall -Wextra -pedantic -O0 -g3 -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls helloworld.o -o helloworld
Tests unitaires
Dans votre dépôt git, vous disposez d'une branche tests
contenant un certain nombre de scripts bash
et de programmes .c
permettant de tester votre code.
Nous exécuterons de manière automatisée (en utilisant le serveur d'intégration continue de la plateforme GitLab) ces tests sur votre code afin de connaître l'état de votre rendu. Vous pouvez consulter ces tests (sans y être obligé) de différentes manières :
- en consultant le contenu de la branche
tests
par l'interface web de la plateforme GitLab - en consultant le contenu de la branche
tests
par l'intermédiaire de la commandegit checkout
(ougit switch
) - en fusionnant la branche
tests
dans votre branchemaster
par l'intermédiaire de la commandegit merge
Exercice 2 : Entrées/sorties et fonctions
-
Dans un fichier
max3.c
, écrivez un programme qui calcule le maximum de 3 valeurs entières.Les trois valeurs à comparer seront précisées dans des variables
a
,b
etc
que vous définirez dans votre programme. Il fera ensuite appel à une fonctionmax3
que vous définirez. Le résultat renvoyé par cette fonction sera affiché sur la sortie standard.Pour répondre à cette question, vous aurez sûrement besoin de consulter un peu de documentation sur les chaînes de format. Vous devriez avoir lu à ce sujet dans le Chapitre 1 "Les bases de la programmation en C" (page 30) du polycopié fourni sur Arche.
-
Compilez et exécutez votre programme.
Quels sont les jeux de tests (les valeurs à passer en paramètre) que vous devez envisager pour s'assurer de la correction de votre programme ? Documentez ces jeux de tests dans un fichier texte
max3_tests.txt
où chaque ligne correspond à une entrée (3 valeurs entières séparées par un espace) à passer en paramètre pour une exécution de votre programme. -
Dans un fichier
max3_stdin.c
, écrivez un programme qui calcule le maximum de 3 valeurs entières.Cette fois-ci, le programme demandera à l'utilisateur de saisir les 3 valeurs entières sur l'entrée standard (une valeur par ligne).
Remarque : Vous pourrez être amené à utiliser la fonction
scanf
de la librairie standard pour lire une valeur entière depuis l'entrée standard. Vous pouvez vous référer au chapitre 1 du polycopié (page 31) ou à la page man de la fonctionman 3 scanf
. -
Dans un fichier
max3_args.c
, écrivez un programme qui calcule le maximum de 3 valeurs entières.Cette fois-ci, le programme demandera à l'utilisateur de passer les 3 valeurs entières en paramètre sur la ligne de commande.
Remarque : Vous serez amené à utiliser la fonction
atoi
de la librairie standard pour convertir une chaîne de caractères en une valeur entière. Là encore, vous devriez consulter la page man associée (man 3 atoi
).
Exercice 3 : Entrées/sorties et tableaux
Il est possible d'identifier le signe astrologique d'une personne en fonction de sa date de naissance. Pour cela, il suffit de consulter le tableau ci-dessous :
Signe | Dates | Signe | Dates | |
---|---|---|---|---|
Bélier | 21/3 au 19/4 | Balance | 23/9 au 22/10 | |
Taureau | 20/4 au 20/5 | Scorpion | 23/10 au 21/11 | |
Gémeaux | 21/5 au 20/6 | Sagittaire | 22/11 au 21/12 | |
Cancer | 21/6 au 21/7 | Capricorne | 22/12 au 19/1 | |
Lion | 22/7 au 22/8 | Verseau | 20/1 au 18/2 | |
Vierge | 23/8 au 22/9 | Poisson | 19/2 au 20/3 |
-
Écrivez un programme
zodiac.c
prenant en paramètre (en argument de la ligne de commande) la date de naissance d'un utilisateur (au format jour/mois/année) et qui affiche en retour son signe astrologique. On imposera que l'année de la date saisie soit positive et non nulle. Si la date saisie n'est pas valide, affichez un message d'erreur et quitter le programme avec un code de retour non nul.Vous découperez votre programme en plusieurs sous fonctions (validation de la date, calcul du signe astrologique, etc.)
Vous proposerez un algorithme reposant sur des tableaux qui mémorisent les signes astrologiques et leur dates d'effet pour réaliser ce programme. (Il ne s'agit pas ici de faire un énorme
if... else... else if...
ni d'utiliser une construction du typeswitch... case...
mais plutôt une variante d'une boucle de recherche).Rappel : On rappelle que les tableaux en C sont des tableaux à taille fixe.
Remarque : Vous pourrez être amené à utiliser la fonction
sscanf
de la librairie standard pour analyser une chaîne de caractères.
Exercice 4 : Entrées/sorties et fonctions
- Écrivez un programme
dayofbirth.c
qui indique le jour de la semaine de naissance de l'utilisateur. Ce jour peut être calculé en utilisant la formule de Zeller (1885) :
ω = j + ⌊2.6 × t - 0.2⌋ + d + ⌊d / 4⌋ + ⌊c / 4⌋ + 5 × c
où :
- j : numéro du jour dans le mois,
- m : numéro du mois dans l'année,
- a : numéro de l'année,
- la notation ⌊x⌋ correspond à la partie entière de x,
- t = m - 2 si m > 2 sinon m + 10
- b = a si m > 2 sinon a - 1
- c = ⌊b / 100⌋
- d = b - 100 × c
ω ≡ 0 (mod 7) si le jour est un dimanche, à 1 (mod 7) si le jour est un lundi, etc.
L'utilisateur devra saisir son prénom ainsi que sa date de naissance sur la ligne de commande (ie. ./dayofbirth "Black Adder" 15/06/1983
). Le résultat sera affiché sur la sortie standard (ie. Black Adder est né(e) un Mercredi
).
-
Écrivez un deuxième programme
dayofbirth_stdin.c
qui effectue les même calculs, mais cette fois demande à l'utilisateur de saisir son nom et sa date de naissance sur l'entrée standard (vous pourriez être amené à utiliser les fonctionsfgets
etstrnlen
).rlyeh:c2k19-lab1.git cthulhu$ ./dayofbirth_stdin Gerald O. 19/03/1978 Gerald O. est né(e) un Dimanche rlyeh:c2k19-lab1.git cthulhu$
Exercice 4 : Programmation modulaire et compilation séparée
L'objectif de cet exercice est de re-découper le code source de l'exercice précédent en plusieurs fichiers sources (.c
) et d'entêtes (.h
) contenant les prototypes des fonctions.
Les fichiers attendus sont :
-
astrological.h
, un fichier d'entêtes contenant les prototypes des fonctions de calcul (signe astrologique et jour de naissance). -
astrological.c
, un fichier de code source contenant le code des fonctions de calcul. -
astrological_main.c
, un fichier de code source principal faisant appel aux fonctions définies dans le fichierastrological.c
. Ce programme lit ces entrées sur la ligne de commande. -
astrological_main_stdin.c
, un fichier de code source principal faisant appel aux fonctions définies dans le fichierastrological.c
. Ce programme lit les valeurs saisies sur l'entrée standard.
-
Ecrivez les différents fichiers d'entêtes et de code source.
Les fonctions à définir devront respecter les indications suivantes :
- la fonction
compute_zodiac
qui prend en paramètre 2 valeurs entières de typeint
(le jour et le mois) et qui retourne le signe astrologique sous la forme d'une chaîne de caractères (char*
) - la fonction
validate_date
qui prend en paramètre 3 valeurs entières de typeint
(le jour et le mois et l'année) et qui retourne une valeur booléenne (typechar
valant 1 si vraie, sinon une valeur nulle). - la fonction
zeller
qui prend en paramètre 3 valeurs entières de typeint
(le jour, le mois et l'année) et qui retourne une valeur entière (typeint
) correspondant au numéro du jour dans la semaine (0 pour Dimanche, 1 pour Lundi, etc.). - la fonction
day_of_week
qui prend en paramètre 3 valeurs entières de typeint
(le jour, le mois et l'année) et qui retourne une chaîne de caractères (typechar*
) indiquant le jour de la semaine correspondant à la date donnée en paramètre.
- la fonction
-
Compilez de manière séparée vos programmes. Vous compilerez :
- d'abord et uniquement
astrological.c
, - puis uniquement
astrological_main.c
(respectivementastrological_main_stdin.c
) - et enfin vous assemblerez
astrological.o
avecastrological_main.o
(respectivementastrological_main_stdin.o
) pour générer l'exécutableastrological_main
(respectivementastrological_main_stdin
)
- d'abord et uniquement
Exercice 5 : Makefile
Dans cet exercice, nous vous demandons d'écrire un fichier makefile
permettant de compiler/re-compiler le code de l'exercice précédent.
Pour connaître la syntaxe spécifique à un fichier makefile
, nous vous invitons à revoir la partie du CM et également à lire la section 7.3 (page 93) du chapitre 7 du polycopié.
Exercice 6 : Transformations de chaînes de caractères
-
Dans des fichiers
stringtools.h
etstringtools.c
, écrivez une fonctionchar min2maj(char c)
qui convertit un caractère minuscule passé en paramètre en sa majuscule associée.Indice : La documentation retournée par la commande
man 7 ascii
devrait vous permettre de trouver une solution simple à ce problème. -
Complétez les fichiers
stringtools.c
etstringtools.h
, en écrivant une fonctionchar maj2min(char c)
qui convertit un caractère majuscule passé en paramètre en sa minuscule associée. -
Écrivez un programme
stringtools_main.c
qui prend en paramètre sur la ligne de commande une chaîne de caractères et qui transforme chaque caractère minuscule en majuscule et inversement. Le résultat sera affiché sur la sortie standard. Votre programme fera usage des fonctions définies dans les questions précédentes.
Exercice 7 : Occurrences d'un caractère dans un mot
-
Dans des fichiers
occurrences.h
etoccurrences.c
, écrivez les fonctions suivantes :- la fonction
int first_occurrence(char c, char str[])
qui renvoie le rang de la première occurrence du caractèrec
dans la chaînestr
si celui-ci est présent sinon elle retourne la valeur -1. - la fonction
int last_occurrence(char c, char str[])
qui renvoie le rang de la dernière occurrence du caractèrec
dans la chaînestr
si celui-ci est présent sinon elle retourne la valeur -1.
Remarque : Vous pourrez être amené à utiliser la fonction
strlen
de la librairie standard. - la fonction
-
Écrivez dans un fichier
occurrences_main.c
un programme qui trouve la première et la dernière occurrence d'un caractère dans un mot. Le mot et le caractère seront lus à partir de l'entrée standard (caractère recherché sur la première ligne, mot sur la seconde, affichage des résultats sur la sortie standard séparés par un espace).rlyeh:c2k19-lab1.git cthulhu$ ./occurrences_main a abcdefga 0 7
-
Généralisez votre programme (dans un fichier
occurrences_main_loop.c
) à une suite de mots entrée au clavier, la saisie du motexit
provoquant la terminaison du programme.
Pour plus tard...
Dans cette section, vous trouverez un pense bête rapide pour créer et configurer un projet "C" dans Visual Studio Code.
Le dépôt de ce TP contient déjà un répertoire .vscode
contenant la configuration adéquate.
Tasks: Configure Default Build Task C/C++: clang générer le fichier actif (/usr/bin/clang)
Dans .vscode/tasks.json
:
{
"version": "2.0.0",
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: clang générer le fichier actif",
"command": "/usr/bin/clang",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "compilateur : /usr/bin/clang"
}
]
}
Tasks: Run Build Task
Run -> Add Configuration... -> C/C++ (GDB/LLDB) -> "clang - Générer et déboguer le fichier actif (/usr/bin/clang)"
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "clang - Générer et déboguer le fichier actif",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "lldb",
"preLaunchTask": "C/C++: clang générer le fichier actif"
}
]
}