Voici quelques exercices à résoudre en langage C...
 
Rappel: la ligne de compilation recommandée est la suivante.
$ gcc -g -Og -Wall -Wextra -o toto toto.c
 

1   Heures - minutes - secondes

Étant données deux durées en secondes, les convertir en heures - minutes - secondes puis les additioner.

2   Années bissextiles

Déterminer si une année est bissextile.

  • une année est bissextile si elle est divisible par 4 et pas par 100,
  • sauf les années divisibles par 400 qui sont bissextiles

3   Dessiner un sapin

Dessiner un sapin de hauteur h. Exemples (h = 4)

  • sapin plein:
           *
          ***
         *****
        *******
    
  • sapin vide:
           *
          * *
         *   *
        *******
    
  • sapin couché:
           *
          **
         ***
        ****
         ***
          **
           *
    

4   Tables de multiplication

Écrire une fonction affichant la table de multiplication d'un entier sous le format (exemple pour 3):

3   6   9   12   15
18   21   24   27   30

puis une autre affichant cette fois-ci la table dans l'ordre:

3   9   15   21   27
6   12   18   24   30


Écrire un programme C affichant les 10 premières tables de multiplication. Le format d'affichage est demandé à l'utilisateur.

Remarque: si une fonction ne retourne rien, son type de retour est void.

5   Deviner un nombre

Écrire un programme qui réalise le petit jeu suivant. Tout d'abord, l'ordinateur choisit un entier x entre 1 et 100. L'utilisateur essaie ensuite de le deviner. Il entre alors successivement des entiers, et à chaque coup l'ordinateur lui indique si l'entier est supérieur à x, inférieur à x, ou égal à x auquel cas la partie s'arrête et le nombre de coups est affiché.

Modifier ensuite le programme afin que l'utilisateur puisse, s'il le souhaite, recommencer une partie. En quittant le programme, le meilleur score s'affiche.

Voici une fonction retournant un entier entre min et max:

#include <stdlib.h>
#include <time.h>
  
int choisir_nombre(int min, int max) {
  srand(time(NULL));
  return min + rand() % (1+max-min);
}

6   Mise en majuscule

Écrire un programme qui lit un texte saisi au clavier, le met en majuscule et écrit le résultat à l'écran. On pourra utiliser la fonction suivante qui prend un caractère en argument, le convertit en majuscule (si besoin) et retourne le résultat:

#include <ctype.h>
int toupper(int c);


On pourra tester ce programme

  • soit en tapant un texte au clavier;
  • soit en lui donnant le contenu d'un fichier par cat pipo.txt | ./toto ou bien ./toto < pipo.txt.

1 Tableaux

Cet exercice a pour seul but de vérifier que vous savez déclarer, construire et utiliser les tableaux en C.

Écrire un petit programme qui déclare un tableau d’entiers de taille prédéfinie puis qui, à l’aide d’un menu interactif, permet d’effectuer les opérations suivantes :

  • afficher la taille du tableau ;
  • afficher le contenu du tableau ;
  • modifier l’élément à l’indice i ;
  • échanger les valeurs de deux éléments ;
  • compter le nombre d’occurrences d’une valeur ;
  • ...

2 Occurrences

Écrire un programme qui lit un texte sur l’entrée standard, compte le nombre d’occurrences de chaque lettre minuscule (’a’. . . ’z’), puis affiche les résultats.

Compléter ensuite le programme pour qu’il compte aussi les lettres majuscules. Le faire afficher les résultats sous forme d’histogramme horizontal (facile) ou vertical (plus difficile).

3 Quel est ce jour ?

Le but de cet exercice est d’écrire un programme permettant de calculer le jour de la semaine correspondant à une date donnée. Pour cela, on va dérouler les jours à partir d’une date de
référence.
Définir une structure permettant de stocker une date avec le jour de la semaine correspondant. Écrire :

  • une fonction calculant le lendemain d’une date donnée ;
  • une fonction calculant la veille d’une date donnée ;
  • une fonction permettant de vérifier l’ordre entre deux dates.

Attention aux années bissextiles.

Écrire ensuite un programme qui donne le jour de la semaine d’une date donnée. Pour cela, le programme utilisera une date dont le jour de la semaine est connu (par exemple, le 1er janvier 2013 est un mardi) puis utilise la fonction lendemain ou veille pour trouver la solution.
On pourra procéder, au choix, de manière itérative ou récursive.

4 Manipulation de chaînes de caractères

Écrire les fonctions de manipulations de chaînes de caractères suivantes :

int my_strlen(const char s[]);

Cette fonction doit retourner la longueur de la chaîne passée en paramètres.

 

void my_strcpy(char s1[], const char s2[]);

Cette fonction doit recopier la chaîne s2 dans la chaîne s1.

 

void my_strcat(char s1[], const char s2[]);

Cette fonction doit ajouter (concaténer) la chaîne s2 au bout de la chaîne s1.

 

int my_strcmp(const char s1[], const char s2[]);

Cette fonction doit comparer les deux chaînes passées en paramètre, et retourner un entier respectivement inférieur, égal ou supérieur à zéro si la chaîne s1 est respectivement inférieure, égale ou supérieure à la chaîne s2, suivant l’ordre lexicographique.


Écrire ensuite un programme permettant de tester ces fonctions.

5 Arguments sur la ligne de commande

Il est possible d’accéder aux paramètres de la ligne de commande en déclarant la fonction principale main de la manière suivante :

int main(int argc , char ∗argv[])
{
    // ...
}


Dans ce cas, argc correspond au nombre d’arguments passés au programme. Le tableau argv est un tableau de chaînes de caractères de taille argc contenant les paramètres passés sur la ligne de commande. Le premier élément argv[0] est le nom utilisé pour lancer le programme.


Écrire un programme affichant la liste des arguments passés sur sa ligne de commande.

Compilation séparée, Makefile

Quelques exercices pour illustrer ce qui a été présenté en TD:

  1. Utiliser un programme simple (Hello World, par exemple) pour tester les commandes gcc -v , gcc -E, gcc -S, gcc -c, … et observer le résultat.
  2. Reprendre un des exercices d'un TP précédent, et répartir le code dan plusieurs fichiers : main() dans un fichier, les autres fonctions dans un ou des autre(s) fichier(s).
    Compiler manuellement, et tester.
  3. Écrire un Makefile pour automatiser la compilation du programme ci-dessus.
    Vérifier son fonctionnement.
  4. Ajouter au Makefile une cible « clean » pour supprimer les fichiers générés (résultats de compilation).
    Tester avec la commande :
    $ make clean

Documentation

Le manuel de GNU make (l'implémentation utilisée sous Linux) est accessible localement avec les pages info :

1 Pour s’échauffer

Soit le fragment de programme suivant :

float a = 0.001;
float b = 0.003;
float c, ∗pa, ∗pb, ∗pp;
pa = &a;
∗pa ∗= 2;
pb = &b;
c = 3 ∗ (∗pb − ∗pa);
pp = pa;

Après exécution, quelles sont les valeurs de a, b, c, pa, ∗pa, &∗pa, pb, ∗pb, pp, ∗pp ? Vérifiez vos
réponses en écrivant le programme affichant les différentes valeurs.

NB: pour afficher la valeur d'un pointeur avec printf(), on pourra utiliser le spécificateur de format "%p".

2 Allocation dynamique

Nous souhaitons écrire un programme permettant de faire quelques statistiques pour un
ensemble de notes dont le nombre n’est pas connu à l’avance. Le programme devra commencer
par demander le nombre de notes à l’utilisateur. Ensuite un tableau de flottants devra être alloué
dynamiquement, avant de lire les notes. Le programme affichera ensuite la valeur minimale, la
valeur maximale, la moyenne et la médiane des notes. La mémoire allouée devra être libérée
avant de quitter le programme.

Rappels

  • Un tableau dynamique de n réels est déclaré et alloué par l’incantation suivante :
    double *tab = malloc(n * sizeof(double));
  • Les éléments, comme pour les tableaux statiques, sont accédés par la notation « crochet » : tab[k] .
  • La mémoire est libérée avec :
    free(tab);

3 Tableaux de tableaux. . .

Pour allouer dynamiquement un tableau à deux dimensions, une solution est de le modéliser
par un tableau de tableaux. Écrire un programme qui :

  • lit deux nombres m et n ;
  • alloue dynamiquement un tableaux d’entiers de m lignes et n colonnes ;
  • remplit le tableau par le produit du numéro de ligne par le numéro de colonne ;
  • affiche le contenu du tableau ;
  • libère la mémoire précédemment allouée.

Indications

  • Le tableau devra être déclaré comme une pointeur de pointeur d’entier. Par exemple,
    int ∗∗a.
  • Un premier tableau (de pointeurs d’entiers) devra être alloué de longueur égale au nombre
    de lignes souhaitées.
  • Chacune des lignes du tableau devra ensuite être allouée de manière indépendante.
  • Les éléments du tableau sont alors accessibles avec la notation « crochet ». Par exemple,
    a[i][j] pour l’élément de la ie ligne, je colonne.
  • La désallocation doit être faite dans l’ordre inverse.

  Plan des savoirs réseaux étudiés

  • TP1 - Configuration à l'"ancienne" du réseau et commandes utiles
    • Enoncé avec les "réponses" / commandes attendues
  • TP2 - Configuration "moderne" du réseau et ssh