Langage C - Exercices

Table des matières

1. Premiers pas

1.1. Exercice 100 - Hello World!   hello world

  1. Dans un editeur de texte, taper le code source suivant :
#include <stdio.h>

int main()
{
    printf("Hello World!\n");
    return 0;
}
  1. Enregistrer le fichier dans hello.c.
  2. Compiler ce fichier à l'aide de l'instruction gcc hello.c. Un fichier a.out a été produit.
  3. Executer ce fichier à l'aide de la commande ./a.out.

1.2. Exercice 102 - Hello World!   hello world reprise

Ecrire et compiler un programme qui affiche :

+------------+
|Hello World!|
+------------+

1.3. Exercice 110 - Afficher une variable   printf declaration variable affectation

  1. Déclarer une variable nommée entier de type int.
  2. Affecter la valeur 42 à cette variable.
  3. Afficher le contenu de cette variable à l'aide de l'instruction :
printf("Le contenu de la variable entier est : %d\n", entier);

On remarque que %d est remplacé par le contenu de la variable entier.

  1. Enlever le \n. Qu'observe-t-on ?
  2. Déclarer une variable de type float et lui affecter la valeur 3.14.
  3. Afficher le contenu de cette variable.

2. Variables et types de base

2.1. Exercice 210 - La taille des differents types   variables types sizeof

A l'aide de l'opérateur sizeof, afficher dans deux colonnes différents types de données (char, int, float, …) ainsi que la place occupée en mémoire par chacun de ces types.

Indication: sizeof ne "retourne" pas un int et ne peut être afficher avec %d; préférer %lu ou %ld.

2.2. Exercice 220 - Représentations d'un entier   variable representation

  1. Déclarer une variable de type int et initialiser la à une valeur de votre choix.
  2. A l'aide de la fonction printf, afficher cette variable en base décimale (à l'aide de %d) , en base hexadécimale (à l'aide de %X) et en base octale (à l'aide de %o).
  3. Répéter l'opération pour quelques valeurs suivantes de la variable.

2.3. Exercice 215 - Représentation d'une variable de type char

  1. Déclarer une variable de type char.
  2. Affecter à cette variable la valeur 65.
  3. Afficher le char à l'aide de %d. Qu'obtient-on ?
  4. Afficher le char à l'aide de %c. Qu'obtient-on ?
  5. Que se passe-t-il lorsque l'on ajoute un petit nombre entier au char ?

2.4. Exercice 230 - Echanger les valeurs de deux variables   variables affectation echange

  1. Déclarer deux variables a et b de type int.
  2. Affecter la valeur 42 la variable a et la valeur 17 à la valeur b.
  3. A l'aide d'un appel à la fonction printf afficher la valeur contenue dans a et la valeur contenue dans b.
  4. Trouver un moyen de mettre la valeur contenue dans a dans b et la valeur contenue dans b dans a.
  5. Afficher de nouveau les contenus de a et b pour vérifier que la manipulation précédente a bien fonctionné.

3. Opérateurs arithmétiques

3.1. Exercice 310 - Les opérateurs arithmétiques

  1. Déclarer deux variables n et m de type int et deux variables x et y de type float.
  2. Affecter une valeur non nulle à chacune de ces variables.
  3. Afficher n+m, n-m, n*m, n/m.
  4. Afficher x+y, x-y, x*y, x/y. Comparer les résultats obtenus avec les résultats obtenus à la question précédente.
  5. Tester l'opérateur %. A quoi sert-il ?

4. Structures conditionnelles

4.1. Exercice 405 - Structure conditionnelle - Connecteurs logiques   if else or

Ecrire un programme qui demande à l'utilisateur de saisir une lettre (minuscule). Le programme doit déterminer s'il s'agit d'une voyelle ou d'une consonne.

4.2. Exercice 410 - Représentation des variables - Structure conditionnelle

Ecrire un programme qui demande à l'utilisateur de saisir un nombre entre 32 et 127 inclus. Si le nombre est inclus dans cet intervalle, le programme doit afficher le caractère dont le code ASCII est ce nombre. Sinon, le programme doit afficher un message et se terminer.

Que signifie l'acronyme ASCII ?

4.3. Exercice 415 - Comparer un entier   comparaison if

Ecrire un programme qui demande à l'utilisateur d'entrer son âge. Le programme doit afficher Vous êtes majeur. si l'âge est supérieur ou égal à 18 ans et Vous êtes mineur. sinon.

4.4. Exercice 420 - Un exemple de choix multiples   switch

Ecrire un programme qui demande à l'utilisateur de choisir un caractère parmi a, b ou c. Le programme doit alors écrire Vous avez choisi a. (resp. b., c.) si l'utilisateur a choisi a (resp. b, c). Sinon, le programme doit écrire Vous avez choisi quelque chose qui n'est pas dans la liste..

5. Les boucles

5.1. Exercice 501   boucles reprise

Ecrire, compiler et exécuter un programme qui affiche :

+------------+
|Hello World!|
+------------+
+------------+
|Hello World!|
+------------+
+------------+
|Hello World!|
+------------+
+------------+
|Hello World!|
+------------+
+------------+
|Hello World!|
+------------+
+------------+
|Hello World!|
+------------+

5.2. Exercice 505 - Motif rectangle   boucles motifs

Afficher un rectangle, consitué du caractère +, de largeur 10 et de hauteur 30.

5.3. Exercice 510 - Motif carré   boucles motifs

Afficher un carré, consitué du caractère +, de coté 30. Le caractère + ne doit pas apparaître deux fois de suite dans le code source.

La carré est-il carré ?

5.4. Exercice 515 - Liste de nombres   boucles entiers

  1. Ecrire un programme qui affiche les 10000 premiers nombres entiers positifs en colonne.
  2. Modifier le programme pour qu'une ligne soit passée tous les dix nombres.

5.5. Exercice 520 - Carrés   boucles motifs

Ecrire un programme qui demande cinq fois de suite un nombre à l'utilisateur et qui à chaque saisie affiche le carré de ce nombre.

5.6. Exercice 525 - Un motif triangulaire   boucles motifs

Ecrire un programme permettannt d'afficher dans la console le motif suivant :

^
^^
^^^
^^^^
^^^^^
^^^^^^
^^^^^^^
^^^^^^^^
^^^^^^^^^

5.7. Exercice 530 - Un motif en losange   boucles motifs

Ecrire un programme permettant d'afficher dans la console le motif suivant :

....^....
...^^^...
..^^^^^..
.^^^^^^^.
^^^^^^^^^
.^^^^^^^.
..^^^^^..
...^^^...
....^....

5.8. Exercice 531 - Un motif en permutation circulaire   boucles motifs

Ecrire un programme permettant d'afficher dans la console le motifif suivant :

JKLMNOPQRSTUVWXYZABCDEFGHI
KLMNOPQRSTUVWXYZABCDEFGHIJ
LMNOPQRSTUVWXYZABCDEFGHIJK
MNOPQRSTUVWXYZABCDEFGHIJKL
NOPQRSTUVWXYZABCDEFGHIJKLM
OPQRSTUVWXYZABCDEFGHIJKLMN
PQRSTUVWXYZABCDEFGHIJKLMNO
QRSTUVWXYZABCDEFGHIJKLMNOP
RSTUVWXYZABCDEFGHIJKLMNOPQ
STUVWXYZABCDEFGHIJKLMNOPQR
TUVWXYZABCDEFGHIJKLMNOPQRS
UVWXYZABCDEFGHIJKLMNOPQRST
VWXYZABCDEFGHIJKLMNOPQRSTU
WXYZABCDEFGHIJKLMNOPQRSTUV
XYZABCDEFGHIJKLMNOPQRSTUVW
YZABCDEFGHIJKLMNOPQRSTUVWX
ZABCDEFGHIJKLMNOPQRSTUVWXY
ABCDEFGHIJKLMNOPQRSTUVWXYZ
BCDEFGHIJKLMNOPQRSTUVWXYZA
CDEFGHIJKLMNOPQRSTUVWXYZAB
DEFGHIJKLMNOPQRSTUVWXYZABC
EFGHIJKLMNOPQRSTUVWXYZABCD
FGHIJKLMNOPQRSTUVWXYZABCDE
GHIJKLMNOPQRSTUVWXYZABCDEF
HIJKLMNOPQRSTUVWXYZABCDEFG
IJKLMNOPQRSTUVWXYZABCDEFGH

Remarque : le décalage initial doit être aléatoire.

5.9. Exercice 532 - Nombre hexadécimaux   boucle table hexadecimaux

  1. Ecrire un programme qui affiche deux colonnes : une colonne avec les nombres entiers de 0 à 255 et une autre colonne avec leurs valeurs en base 16 (héxadécimale).
  2. Bonus: transformer le code pour obtenir 8 fois 2 colonnes de 16 nombres

5.10. Exercice 535 - Table ASCII   boucles char ascii

Ecrire un programme qui affiche les caractères correspondant aux codes ascii allant de 33 à 127, à l'aide de trois colonnes :

  • la première colonne affiche le caractère
  • la deuxième colonne affiche le code du caractère en base 10
  • la troisième colonne affiche le code du caractère en base 16

5.11. Exercice 540 - Code golf   boucles int golf

Ecrire un programme qui affiche en colonne les entiers naturels de 0 à 100. Le code source doit prendre le moins de caractères possible.

5.12. Exercice 545 - Dépassement de capacité   boucles depassement capacite

Ecrire un programme qui déclare une variable de type unsigned char et une variable de type char. Coder une boucle de 500 itérations. A chaque itération, afficher chacune des deux variables précédentes puis incrémenter ces deux variables. Il doit y avoir deux colonnes dans la console : une pour chaque variable. Que constate-t-on ?

5.13. Exercice 550 - Dépassement de capacité et comparaison   boucles depassement capacite comparaison entier signe

Afficher les 127 premiers entiers naturels à l'aide d'une boucle dont le compteur est un char. Qu'observe-t-on ?

5.14. Exercice 555 - Dépassement de capacité II   boucles depassement capacite sizeof int

Déterminer (à l'aide d'une boucle, par exemple) le plus grand entier naturel qu'il est possible de stocker dans int. En déduire le nombre de bits, puis le nombre d'octets sur lequel est codé un int.

Indication: le bit le plus à gauche sert à code le signe de l'int.

5.15. Exercice 570 - Fonction puissance

Ecrire une fonction int puissance(int x, int p) qui calcule \(x^{p}\).

5.16. Exercice 575 - Table de multiplications

Ecrire un programme qui affiche la table de multiplication suivante :

 1   2   3   4   5   6   7   8   9  10
 2   4   6   8  10  12  14  16  18  20
 3   6   9  12  15  18  21  24  27  30
 4   8  12  16  20  24  28  32  36  40
 5  10  15  20  25  30  35  40  45  50
 6  12  18  24  30  36  42  48  54  60
 7  14  21  28  35  42  49  56  63  70
 8  16  24  32  40  48  56  64  72  80
 9  18  27  36  45  54  63  72  81  90
10  20  30  40  50  60  70  80  90 100

5.17. Exercice 576 - Afficher un tableau   boucles tableau

Ecrire un programme qui produit la sortie ci-dessous. Le programme doit utiliser des boucles.

 1  11  21  31  41  51  61  71  81  91
 2  12  22  32  42  52  62  72  82  92
 3  13  23  33  43  53  63  73  83  93
 4  14  24  34  44  54  64  74  84  94
 5  15  25  35  45  55  65  75  85  95
 6  16  26  36  46  56  66  76  86  96
 7  17  27  37  47  57  67  77  87  97
 8  18  28  38  48  58  68  78  88  98
 9  19  29  39  49  59  69  79  89  99
10  20  30  40  50  60  70  80  90 100

5.18. Exercice 580 - Saisir une chaîne de caractères   boucles tableau scanf

Ecrire un programme dans lequel un tableau de 30 char est déclaré. Afficher un message demandant à l'utilisateur de saisir son nom. A l'aide de la fonction scanf, stocker le nom qu'à tapé l'utilisateur dans le tableau de char précedemment déclaré.

Afficher la troisième lettre du nom.

5.19. Exercice 585 - Permutation circulaire d'une chaîne de caractères   boucles tableau scanf

Ecrire un programme dans lequel un tableau de 30 char est déclaré. Afficher un message demandant à l'utilisateur de saisir un mot. A l'aide de la fonction scanf, stocker le mot qu'à tapé l'utilisateur dans le tableau de char précedemment déclaré. Le programme doit afficher toutes les permutations circulaires du mot.

Voici un exemple d'exécution du programme :

Veuillez saisir un mot : bonjour
bonjour
onjourb
njourbo
jourbon
ourbonj
urbonjo
rbonjou

Indication: il est possible d'utiliser la fonction strlen de la librairie string.h qui donne la longeur d'une chaîne de caractères.

6. Fonctions

6.1. Exercice 601 - Une première fonction   fonction aire float

  1. Rappeler la formule qui donne l'aire du disque.
  2. Ecrire une fonction de prototype float aire_disque(float rayon):

    • qui prend en entrée un réel noté rayon
    • qui retourne l'aire du disque de rayon rayon

    On écrira cette fonction avant la fonction main.

  3. Dans la fonction main, apppeler la fonction aire_disque.

6.2. Exercice 602 - Aire d'un rectangle   fonction aire rectangle float

  1. Rappeler la formule qui donne l'aire du rectangle.
  2. Ecrire une fonction de prototype float aire_rect(float largeur, float longueur):
    • qui prend en entrée deux réels notés largeur et longueur
    • qui retourne l'aire du rectangle correspondant
  3. Dans la fonction main, apppeler la fonction aire_rect.

6.3. Exercice 605 - Majuscule   fonctions char if

Ecrire une fonction de prototype int est_majuscule(char c) qui retourne 1 si c fait partie des caractères ABCDEFGHIJKLMNOPQRSTUVWXYZ et 0 sinon.

6.4. Exercice 610 - Minuscule   fonctions char if

Ecrire une fonction de prototype int est_minuscule(char c) qui retourne 1 si c fait partie des caractères abcdefghijklmnopqrstuvwxyz et 0 sinon.

6.5. Exercice 615 - Caractère alphanumérique   fonctions char alphanumerique if

Ecrire une fonction de prototype int est_alpha_numerique(char c) qui retourne 1 si c fait partie des caractères "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" et 0 sinon.

Les appels suivants, par exemple :

printf("est_alpha_numerique('D') = %d\n", est_alpha_numerique('D'));
printf("est_alpha_numerique('u') = %d\n", est_alpha_numerique('u'));
printf("est_alpha_numerique('9') = %d\n", est_alpha_numerique('9'));
printf("est_alpha_numerique('%') = %d\n", est_alpha_numerique('%'));

doivent afficher :

1
1
1
0

6.6. Exercice 620 - Chiffre   fonctions char digit chiffre

Ecrire une fonction de prototype int est_chiffre(char c) qui retourne 1 si c fait partie des caractères "0123456789" et 0 sinon.

6.7. Exercice 625 - Somme d'entiers   fonctions somme entiers boucles

Ecrire une fonction somme qui prend en paramètre un int n et qui retourne la somme de tous les entiers compris entre 0 et n. Afficher la somme des 100 premiers entiers.

6.8. Exercice 630 - Factorielle   fonctions factorielle iteration boucles

Ecrire une fonction qui calcule \(k!\).

On rappelle que pour \(k\geq 1,\;k!=k\times(k-1)\times\dots\times 2\times 1\). Par exemple, \(4!=4\times 3\times 2\times 1\) et \(7!=7\times 6\times 5\times 4\times 3\times 2\times 1\). Par convention, \(0!=1\).

6.9. Exercice 635 - Approximation de l'exponentielle

On rappelle le développement en série entière de l'exponentielle : \[\exp(x)=\sum_{k=0}^{+\infty}\frac{x^{k}}{k!}\]

Ecrire une fonction de prototype double expo(double x, int n). Cette fonction doit retourner la somme partielle, pour k allant de 0 à n, du développement ci-dessus.

6.10. Exercice 646 - Echanger deux valeurs d'un tableau   tableau echange valeurs

Ecrire une fonction de prototype void echanger(int tab[], int i1, int i2) qui échange les valeurs du tableaux se trouvant aux positions i1 et i2. On fera l'hypthèse que i1 et i2 sont des entiers positifs ou nuls inférieurs à la taille du tableau passé en paramètre.

6.11. Exercice 650 - Copie locales des variables   variables locales

On donne le code suivant :

#include <stdio.h>

void f(int i)
{
    i = i+1;
}

int main()
{
    int i = 42;
    printf("i = %d\n",i);
    // f(i);
    printf("i = %d\n",i);
    return 0;
}
  1. Compiler et tester le code ci-dessus.
  2. Décommenter l'instruction commmentée. A quoi peut-on s'attendre ?
  3. Tester. Qu'observe-t-on ? Comment expliquer cela ?
  4. Afficher les adresses des différentes variables.

6.12. Exercice 660 - Changer l'ordre

Ecrire une fonction de prototype void changer_ordre(int tab[], int taille). Cette fonction doit échange la première valeur du tableau avec la dernières, la deuxième valeur du tableau avec l'avant dernière, etc…

Par exemple, le code

int tab1[5] = {11,12,13,14,15};
int tab2[4] = {10,20,30,40};

afficher_tab(tab1, 5);
changer_ordre(tab1, 5);
afficher_tab(tab1, 5);

afficher_tab(tab2, 4);
changer_ordre(tab2, 4);
afficher_tab(tab2, 4);

doit produire l'affichage

11
12
13
14
15
15
14
13
12
11
10
20
30
40
40
30
20
10

6.13. Exercice 690 - Passer une fonction à une fonction

On donne les fonctions :

#include <stdio.h>

\\ Une fonction très simple
double f(double x) {
    return x;
}
\\ Calcul de l'intégrale à l'aide de la méthode des rectangles
double integrale(double f, double a, double b, int n) {
    double h = (b-a) / n;
    double aire = 0;
    for(int i = 0; i < n; i++) {
      aire += h * f(a+i*h);
    }
    return aire;
}
  1. Après avoir copié-collé ces deux fonction dans un fichier, tester la fonction integrale en l'appelant dans la fonction main. Qu'observe-t-on ?
  2. A l'aide du message d'erreur fourni par le compilateur, corriger la signature de la fonction integrale, autrement dit, corriger le type du paramètre f.

7. Tableaux

7.1. Tableaux 700 - Déclarer un tableau

  1. Déclarer un tableau de 5 entiers nommé tab1 à l'aide de l'instruction

    int tab1[5];

  2. Affecter la valeur 10 dans la case d'indice 0 du tableau à l'aide de l'instruction

    tab1[0]=10;

  3. Affecter des valeurs aux quatres autres cases du tableau tab1. Quel est l'indice de la dernière case ?
  4. Tester l'instruction :

    int tab2[8] = {-5, 10, 20, 15, 0, 0, 100, 1000};

  5. Afficher le contenu de la case d'indice 2 de tab2.
  6. Afficher le contenu de toutes les cases à l'aide d'une boucle.

7.2. Exercice 720 - Tableaux

Ecrire un programme qui déclare un tableau de 20 int. A l'aide d'une boucle, affecter la valeur \(2^{i}\) dans la case d'indice i du tableau. Afficher ensuite la case d'indice 3, la case d'indice 10 et la case d'indice 19.

7.3. Exercice 730 - Afficher un tableau

Ecrire une fonction void afficher_tableau(int tab[], int taille) qui prend en paramètres un tableau et sa taille. Cette fonction affiche en colonne chaque case du tableau.

7.4. Exercice 750 - Moyenne - Tableau en paramètre

Ecrire une fonction de prototype double moyenne(double notes[], int n) qui retourne la moyenne des notes contenus dans le tableau passé en paramètre.

7.5. Exercice 760 - Recherche de minimum

Ecrire une fonction de prototype int minimum(int tab[], int taille). Cette fonction retourne l'indice de la valeur minimale du tableau.

7.6. Exercice 770 - Recherche dans un tableau

Ecrire une fonction de prototype int rechercher(int tableau[], int taille, int nombre). Cette fonction doit retourner 1 si nombre est dans tableau et retourner 0 si nombre n'est pas dans tableau.

7.7. Exercice 772 - Tableaux et adresses   tableaux vocalbulaire adresse

  1. Déclarer un tableau de 10 int.
  2. Initialiser ce tableau avec des valeurs non nulles.
  3. A l'aide d'une boucle afficher :
    1. les valeurs contenues dans les cases du tableau
    2. les adresses des cases des tableaux
  4. Quelle est la différence entre deux adresses consécutives ? Que peut-on en déduire ?
  5. Recommencer 1., 2., 3. et 4. avec un tableau de double.

7.8. Exercice 775 - Déterminer si un tableau est trié   complexite lineaire n

Ecrire une fonction de prototype int est_trie(int tab[], int taille) qui retourne 1 si le tableau passé en paramètre est trié et qui retourne 0 sinon. Tester la fonction.

7.9. Exercice 780 - Garnir un tableau

Ecrire une fonction de prototype void garnir(int tab[], int taille) qui demande à l'utilisateur d'entrer au clavier autant d'entiers qu'il y a de cases dans le tableau. La fonction stocke les entiers saisis dans le tableau.

7.10. Exercice 790 - Garnir aléatoirement un tableau

Ecrire une fonction void garnir_aleatoirement(int tab[], int taille, int m, int M) qui prend en paramètres un tableau de int ainsi que sa taille. La fonction doit remplir le tableau de nombres entiers aléatoires uniformément répartis entre m et M inclus.

8. Récursivité

8.1. Exercice 800 - Factorielle   fonctions recursives factorielle

Ecrire une fonction récursive de prototype int fact_rec(int n) qui prend en paramètres un entier n et retourne n!.

8.2. Exercice 810 - Fibonacci   fonctions recursives fibonacci

La suite de Fibonacci est la suite de nombres 0, 1, 1, 2, 3, 5, 8, 13, … où le \(i^{ieme}\) nombre \(F_{i}\) de la suite est la somme des deux précédents : \(F_{i}=F_{i-1}+F_{i-2}\) avec \(F_{0}=0\) et \(F_{1}=1\).

Implémenter une fonction récursive int fibo_rec(int i) qui prend en paramètre un indice \(i\) et retourne le \(i^{ieme}\) terme \(F_{i}\) de la suite de Fibonacci.

8.3. Exercice 820 - Somme et produit de deux entiers   fonctions recursives somme produit

  1. Ecrire une fonction récursive de prototype int somme_rec(int a, int b) qui retourne la somme de a et de b. On pourra dans un premier temps supposer a et b positifs.
  2. Ecrire une fonction récursive de prototype int produit_rec(int a, int b) qui retourne le produit de a et de b.

8.4. Exercice 830 - \(\frac{x^{n}}{n!}\)   fonctions recursives exponentielle

On note \(u(n,x)=\frac{x^{n}}{n!}\). On remarque que \(\frac{x^{n}}{n!}=\frac{x}{n}\frac{x^{n-1}}{(n-1)!}\), ce qui signifie que \(u(n,x)\) peut être défini par récurrence : \(\begin{cases}u(n,x)=\frac{x}{n}*u(n-1,x)\;\text{si}\;n\geq 1\\u(0,x)=1\;\text{sinon}\end{cases}\)

Ecrire une fonction récursive de prototype double u(int n, double x) qui prend en paramètre un entier \(n\) et un réel x et qui retourne \(\frac{x^{n}}{n!}\).

8.5. Exercice 840 - Une autre implémentation de l'exponentielle   fonctions recursives exponentielles

Soit \(x\) un réel quelconque. On définit la suite \(exp(n,x)\) par \(\begin{cases}exp(n,x)=exp(n-1,x)+\frac{x^{n}}{n!}\;\text{si}\;n\geq 1\\exp(0,x)=1\end{cases}\)

Ecrire une fonction récursive double exp_rec(int n, double x) qui prend en paramètre un entier \(n\) et un réel \(x\) et qui retourne \(exp(n,x)\).

8.6. Exercice 850 - Recherche de minimum   fonctions recursives recherche minimum tableaux

Exercice une fonction récursive de prototype int indice_du_min_rec(int tab[], int taille). Cette fonction retourne l'indice du minium du tableau passé en paramètre.

Indication: le minimum d'un tableau est le minimum entre sa première valeur et le minimum du sous-tableau commençant à la case d'indice 1. Que dire alors des indices ?

8.7. Exercice 860 - Récursivité terminale - Fibonacci   fonctions recursives terminales fibonacci

Ecrire une fonction int fibo_rec_term(int i, int acc1, int acc2) récursive terminale qui retourne le nombre de Fibonacci d'indice l'entier passé en paramètre.

8.8. Exercice 870 - Afficher un tableau récursivement   fonctions recursives tableau

Ecrire une fonction récursive de prototype void afficher_tab_int_rec(int tab[], int taille) qui permet d'afficher un tableau d'entiers.

8.9. Exercice 880 - Afficher une chaîne de caractères récursivement   fonctions recursives chaine

Ecrire une fonction récursive de prototype void afficher(char * chaine) qui permet d'afficher une chaîne de caractères.

9. Entrées / sorties ordinaires

9.1. Exercice 910 - Lire un caractère   getchar

  1. Tester le code suivant :

    #include <stdio.h>
    
    int main()
    {
        getchar();
    }
    
  2. Que se passe-t-il ?
  3. Récupérer la valeur retourner par getchar dans une variable de type char.
  4. Afficher la valeur valeur récupérée.

Remarque : la fonction getchar peut être utilisée pour interrompre l'excution d'un programme.

9.2. Exercice 920 - Une première entrée clavier

Ecrire un programme qui demande à l'utilisateur d'entrer un entier, le stocke dans une variable puis affiche l'entier entré. Comment faire la même chose pour deux entiers ?

9.3. Exercice 930 - Analyser une chaîne de caractère I   scanf chaine

Ecrire un prgramme qui demande à l'utilisateur d'entrée une chaîne de caractères sous la forme hh:mm:ss.ss (heure, minutes, secondes). Le programme dot enregistrer le nombre d'heures dans un int, le nombre de minutes dns un autre int et le nombre de seconde dans un float.

Le programme doit ensuite afficher l'heure au format hh-mm-ss.ss.

Indication: utiliser la fonction scanf avec des %d et %f convenblemen choisis.

9.4. Exercice 940 - Analyser une chaîne de caractères II   scanf chaine

On sait que %s= dans scanf va lire une chaîne de caractères jusqu'au prohain espace. Que faire alors si l'on souhaite que l'espace fase partie de la chaîne de caractères?

Il faut utilser les fonctionnalités avancées de scanf. Il est possible de réciser à scanf les caractères à conserver à l'aide de la syntaxe []. Par exemple %[abcdefghijklmnopqrstuvwxyz ] (observez l'space après le z) conservera n'importe quelle minuscule ainsi qu'un space.

  1. Tester lecode ci-après en entrant différentes chaînes de caractères (des minucules, des majuscules, des espaces, pas d'espace, …) :

    char str[00];
    scanf("%[bcdefghijklmnopqrstuvwxyz ]", str);
    printf("%n",str);
    
  2. Ecrie l'instruction scanf qui permet de conserver une chaîne decaractère consituée de majuscules ou d'espace, jusqu'à rencontre le caractère ;.
  3. Ecrire un instruction scanf qui permet de conserver la première chaîne decaractères contituées de minuscules et d'espaces et étant délimitéepas les caractères ;. Par exemple si on tape

    BLABLA;bnjour toto;blabla bla

    on consere bonjour toto.

#include <tdio.h>

int main(vid)
{
    char str100];
    char str[100];
    char str[100];
    scanf("%ABCDEFGHIJKLMNOPQRSTUVWXYZ ];", str);
    printf("s\n", str);
    scanf("%^; ];%[abcdefghijklmnopqrstuvwxyz ];",str1,str2);
    printf("s\n%s\n",str1,str2);
    return 0
}

9.5. Exercice 950 - Analyser une chaîne de caractères III   scanf chaine

Ecrire un programme qui demande à l'utilisateur d'entrée une chaîne de caractères au clavier. On suppose que la chaîne de caractères saisie comporte au plus 2 caractères ;. Le programme doit couper la chaîne au niveau des ;. Les caractères acceptés sont les minuscules de a jusque z, les majuscules de A jusque Z et les chiffres de 0 jusque 9. Par exemple si on tape :

BLA bla 12;toto va bien;bonjour! titi

le programme doit stocker :

  • BLA bla 12 dans une première chaîne de caractères
  • toto va bien dans une seconde chaîne de caractères et
  • bonjour dans une troisème chaîne de caractères

10. Pointeurs

10.1. Exercice 1000 - Adresse mémoire d'une variable   pointeurs adresse

Dans la fonction main, déclarer une variable de type int, une variable de type double et une variable de type unsigned char. Afficher les adresses mémoire de chacune de ces variables.

10.2. Exercice 1010 - Adresses mémoire des cases d'un tableau   pointeurs adresse tableaux

Déclarer un tableau de 10 int. A l'aide d'une boucle, afficher les adresses mémoire de chacune des 10 cases du tableau. Qu'observe-t-on ? Quelle hypothèse peut-on faire sur la quantité de mémoire occupée par un int ?

10.3. Exercice 1020 - Une variable et son adresse   pointeurs esperluette

  1. Ecrire un programe dans lequel :
    1. une variable n de type int est déclarée
    2. l'adresse de la variable n est affichée
    3. l'adresse de la variable n est stockée dans une variable nommée adr de type int *
    4. l'addrese de n est affichée à l'aide de la variable adr
  2. Afficher le contenu de n à l'aide de adr.

Indication: utiliser l'opérateur &.

10.4. Exercice 1030 - Incrémenter une adresse - Arithmétique des pointeurs

  1. Déclarer une variable c de type char.
  2. Stocker l'adresse de c dans une variable adr_c de type char *.
  3. Afficher la valeur de adr_c et celle de adr_c+1. Que constate-t-on ?
  4. Recommencer les trois étapes ci-dessus avec une variable n de type int. Qu'observe-t-on ?
  5. Avec une variable de type double ?

Indication: utiliser %p pour afficher les résultats

10.5. Exercice 1040 - Un substitut à sizeof   adresse conversion pointeur

Ecrire un programme qui calcule la différence entre deux entiers consécutifs d'un tableau. Cette différence indique le nombre d'octets sur lesquels est codé un int.

10.6. Exercice 1050 - Tableau et pointeurs

Déclarer un tableau tab de double. Afficher &tab[0] et tab. Que constate-t-on ?

Indication: %d ne fonctionnera pas; il faut utiliser %p.

Bonus: de & et [ ], quel est l'opérateur prioritaire ?

10.7. Exercice 1060 - Parcourir un tableau en itérant sur les adresses

  1. Déclarer et initialiser un tableau d'entiers.
  2. Afficher les éléments de ce tableau en colonne à l'aide d'une boucle, sans utiliser la notation [].
  3. Ajouter une colonne avec l'adresse de la case du tableau affichée.

Indication: lorsque l'on déclare int tab[10], la variable tab contient l'adresse de la première case du tableau.

10.8. Exercice 1070 - Modifier une variable à l'aide d'une fonction

Ecrire une fonction de prototype void incrementer(???) qui permet d'incrémenter une variable de type int.

11. Modularité - Organisation du code

11.1. Exercice 1100 - Un premier .h

  1. Ecrire un fichier fonctions_utiles.c qui contient une fonction void afficher_tab_int(int tab[], int taille), qui permet d'afficher un tableau. Ce fichier ne contient pas la fonction main.
  2. Ecrire un fichier fonctions_utiles.h qui contient le prototype de cette fonction. Ce fichier doit contenir le code suivant :
#ifndef FONCTIONS_UTILES
#define FONCTIONS_UTILES

void afficher_tab_int(int tab[], int taille);

#endif
  1. Ecrire un fichier main.c :
    1. qui inclut le fichier fonctions.h à l'aide de l'instruction #include "fonctions_utiles.h"
    2. qui contient la fonction main dans laquelle est déclaré un tableau de int
    3. qui affiche ce tableau à l'aide de la fonction afficher_tab_int
  2. Compiler à l'aide, par exemple, de gcc fonctions.c main.c -o mon_executable.

11.2. Exercice 1110 - Compilation séparée

Reprendre l'exercice précédent en compilant séparément fonctions.c et main.c.

11.3. Exercice 1120 - Fonctions utiles

Ajouter une fonction de prototype void afficher_tab_double(double tab[], int taille) aux fichiers fonctions_utiles.c et fonctions_utiles.h. Cette fonction doit afficher en colonne un tableau de double dont on connaît la taille.

11.4. Exercice 1130 - Fonctions utiles II

Ajouter une fonction de prototype void afficher_tab_char(char tab[], int taille) aux fichiers fonctions_utiles.c et fonctions_utiles.h. Cette fonction doit afficher en colonne un tableau de char dont on connaît la taille.

12. Les fichiers

12.1. Exercice 1200 - Lire un fichier I   fichier fgetc CRLF

  1. Télécharger le fichier communes-departement-region.csv.
  2. Lire la documentation de la fonction fgetc.
  3. Ecrire un programme qui ouvre le fichier communes-departement-region.csv qui affiche chaque caractère contenu dans ce fichier.

12.2. Exercice 1201 - Lire un fichier II   fichier lecture CRLF

  1. Télécharger le fichier Fruit-Prices-2022.csv.
  2. Lire la documentation de la fonctions fgets.
  3. Ecrire un programme qui ouvre le fichier Fruit-Prices-2022.csv en lecture, puis qui affiche la première ligne du fichier.
  4. Modifier le programme pour qu'il affiche toutes les lignes du fichier.
  5. Faire précéder chaque ligne du numéro de ligne.
  6. Afficher les lignes 30 à 40.
  7. Appliquer le programme au fichier liste-coordonnees-gps-monuments.csv. Qe constate-t-on ?

12.3. Exercice 1202 - Lire un fichier III   fichiers lecture

Ecrire un fichier bonjour.txt qui contient quelques lignes de texte.

Ecrire un programme qui :

  1. ouvre le fichier bonjour.txt
  2. compte et affiche le nombre de lignes
  3. affiche chaque ligne du fichier, précédée de son numéro

12.4. Exercice 1205 - Compter les caractères d'un fichier

  1. Créer un fichier entree.txt qui contient du texte.
  2. Ecrire un programme qui :
    1. ouvre le ficher entree.txt en lecture
    2. donne le nombre de caractères contenus dans ce fichier

12.5. Exercice 1207 - Compter les différentes lettres d'un fichier

  1. Créer un fichier entree.txt qui contient du texte constitué uniquement des caractères de la table ASCII.
  2. Ecrire un programme qui :
    1. ouvre le ficher entree.txt en lecture
    2. compte chaque caractère contenu dans le fichier : compte les 'a', les 'b', …, les 'A', les 'B', …, les '+', les '-', … TOUS les caractères
    3. affiche le décompte final de tous les caractères

12.6. Exercice 1210 - Ecrire dans un fichier   fichiers ecriture

Ecrire un programme qui produit un fichier table_ascii.txt pour les caractères dont le code est compris entre 32 et 127.

Indication: utiliser la fonction fprintf.

12.7. Exercice 1215 - Transformer un fichier

  1. Créer un fichier entree.txt qui contient du texte avec des majuscules et des minuscules.
  2. Ecrire un programme qui :
    1. ouvre le fichier entree.txt en lecture
    2. ouvre un fichier sortie.txt en écriture
    3. lit chaque caractère du fichier d'entrée à l'aide de la fonction fgetc
    4. si le caractère lu est une minuscule, alors le caractère est écrit en majuscule dans le fichier de sortie
    5. sinon le caractère est écrit tel quel dans le fichier de sortie
  3. Ferme les deux fichiers.

12.8. Exercice 1220 - Conversion hexadécimal   fichiers conversion hexadecimal

Ecrire un programme qui produit un fichier table_conversion_hexadecimal.txt. Ce fichier contient deux colonnes:

  • une première colonne avec les nombres de 0 à 100 écrits en base 10
  • une deuxième colonne avec les nombtes de 0 à 100 écrits en base 16

12.9. Exercice 1230 - Table de multiplication au format CSV   fichiers ecritures table csv

Un ficher CSV (comma-separated values) est un ficher texte contenant des données séparée par des virgules. Les données en questions proviennent d'un tableau. Par exemple, le tableau

Nom Age
Toto 19
Jeanjean 22

peut être représenté par un fichier CSV dont le contenu est:

Nom,Age
Toto,19
Jeanjean,22

Ecrire un programme qui demande à l'utilisateur un nombre entier n compris entre 1 et 10. Le programme doit produire un fichier table.csv contenant la table (de multiplication) de n.

12.10. Exercice 1240 - Transposition   fichiers lecture ecriture transposition

Ecrire un programme qui transpose un fichier.

Indication: utiliser fgets.

12.11. Exercice 1250 - Lire un fichier en mode binaire   fichiers lecture mode binaire

  1. Télécharger le fichier paysage1.bmp.
  2. Afficher les propriétés du fichiers et déterminer :
    1. le nombre d'octets que pèse le fichier
    2. le nombre de pixels de large de l'image
    3. le nombre de pixels de haut de l'image
  3. Lire brièvement le format de l'entête d'un fichier bmp.
  4. Ecrire un programme qui ouvre le fichier paysage1.bmp en lecture en mode binaire.
  5. Faire en sorte que le programme lise :
    • le nombre magique
    • la taille du fichier
    • le premier nombre réservé pour l'application qui a créé le fichier
    • le deuxième nombre réservé
    • l'offset pour le contenu effectif du BMP
    • la taille de l'en-tête du fichier
    • la largeur de l'image en pixels
    • la hauteur de l'image en pixels
  6. Afficher ces informations à l'écran.

Indication: il est possible d'utiliser la fonction fread de la librairie stdio.h.

12.12. Exercice 1260 - Produire une image   fichiers ecriture mode binaire

La table ci-dessous a été constituée à partir de l'article wikipedia décrivant le format d'un fichier .bmp. Elle décrit la signification des 54 premiers octets constituant un fichier .bmp. Ces octets contiennent des méta-données sur l'image.

Les octets qui suivent décrivent les quantités de bleu, de vert et de rouge (dans cet ordre) pour chacun des pixels constituant l'image, ligne par ligne.

Par exemple, l'octet 54 décrit la quantité de bleu du pixel tout en haut à gauche de l'image tandis que l'octet 58 donne la quantité de vert du pixel voisin.

Offset (bytes) Size (bytes) Description
0 2 The header field used to identify the BMP and DIB file is 0x42 0x4D in hexadecimal, same as BM in ASCII. The following entries are possible:
BM
Windows 3.1x, 95, NT, ... etc.
BA
OS/2 struct bitmap array
CI
OS/2 struct color icon
CP
OS/2 const color pointer
IC
OS/2 struct icon
PT
OS/2 pointer
2 4 The size of the BMP file in bytes
6 2 Reserved; actual value depends on the application that creates the image, if created manually can be 0
8 2 Reserved; actual value depends on the application that creates the image, if created manually can be 0
10 4 The offset, i.e. starting address, of the byte where the bitmap image data (pixel array) can be found.
14 4 the size of this header, in bytes (40)
18 4 the bitmap width in pixels (signed integer)
22 4 the bitmap height in pixels (signed integer)
26 2 the number of color planes (must be 1)
28 2 the number of bits per pixel, which is the color depth of the image. Typical values are 1, 4, 8, 16, 24 and 32.
30 4 the compression method being used. See the next table for a list of possible values
34 4 the image size. This is the size of the raw bitmap data; a dummy 0 can be given for BI_RGB bitmaps.
38 4 the horizontal resolution of the image. (pixel per metre, signed integer)
42 4 the vertical resolution of the image. (pixel per metre, signed integer)
46 4 the number of colors in the color palette, or 0 to default to 2n
50 4 the number of important colors used, or 0 when every color is important; generally ignored
  1. Qu'est-ce qu'un fichier bmp ?

On donne le code suivant

#include <stdio.h>
#include <math.h>

int main()
{
    char nom_fichier[20] = "image.bmp"; /* Attention au chemin */
    FILE * ressource_fichier;

    char nombre_magique[3] = "BM";
    short int id_app1 = 0;
    short int id_app2 = 0;
    int largeur = 800;
    int hauteur = 600;
    int bpp = 24; // bits par pixel
    int taille_metadonnees = 54;
    int taille_image = ;
    int taille_fichier = taille_image + taille_metadonnees;
    int taille_entete = 40; // De l'octet 14 à l'octet 54
    char b, g, r;

    ressource_fichier = fopen(nom_fichier, "wb");

    if(ressource_fichier != NULL)
      {
        printf("Le fichier est ouvert convenablement.\n");
        /* L'entête d'un bmp tient sur 14 octet */
        fwrite(&nombre_magique, 2, 1, ressource_fichier); // Octet 0
        fwrite(&taille_fichier, 4, 1, ressource_fichier);
        fwrite(&id_app1, 2, 1, ressource_fichier);
        fwrite(&id_app2, 2, 1, ressource_fichier);
        fwrite(&taille_metadonnees, 4, 1, ressource_fichier);

        fwrite(&taille_entete, 4, 1, ressource_fichier); // Octet 14
        fwrite(&largeur, 4, 1, ressource_fichier);
        fwrite(&hauteur, 4, 1, ressource_fichier);

        fputc(1, ressource_fichier); // Octet 26
        fputc(0, ressource_fichier);
        fwrite(, 2, 1, ressource_fichier);

        fputc(0, ressource_fichier); // Octet 30
        fputc(0, ressource_fichier);
        fputc(0, ressource_fichier);
        fputc(0, ressource_fichier);

        fwrite(&taille_image, 4, 1, ressource_fichier); // Octet 34

        for(int i = 0; i < 16; i++) // Octets 38 à 54
          {
            fputc(0, ressource_fichier); 
          }

        for (int i = 0; i < hauteur; i++) {
          for (int j = 0; j < largeur; j++) {
            b = 0;
            g = 0;
            r = 0;
            fwrite(&b,1,1,ressource_fichier);
            fwrite(&g,1,1,ressource_fichier);
            fwrite(&r,1,1,ressource_fichier);
          }
        }

        printf("Nombre magique : %s\n", nombre_magique);
        printf("Taille du fichier : %d\n", taille_fichier);
        printf("Identifiant application 1 : %d\n", id_app1);
        printf("Identifiant application 2 : %d\n", id_app2);
        printf("Taille_Metadonnees : %d\n", taille_metadonnees);
        printf("Taille en-tete : %d\n", taille_entete);
        printf("Largeur : %d\n", largeur);
        printf("Hauteur : %d\n", hauteur);

        fclose(ressource_fichier);
      }
    else
      {
        printf("Erreur lors de l'ouverture du fichier.\n");
      }

    return 0;
}
  1. Combien de bits sont utilisés pour un pixel ? Combien d'octets cela fait-il ? A quoi correspondant chaque octet ?
  2. Comment calculer la taille d'une image en pixel ? En octets ?
  3. Copier-coller le code proposé. Compiler. Y a-t-il des erreurs ? Si oui, les corriger.
  4. Une fois la compilation réussie. Lancer l'exécutable obtenu. Que se passe-t-il ?
  5. Identifier la partie du code qui donne leurs couleurs aux pixels.
  6. Produire un gradient de couleurs.
  7. Produire autre chose.

13. Les chaînes de caractères

13.1. Exercice 1300 - Introduction aux chaînes de type C

En C une chaîne de caractère un tableau de char avec la particularité de se finir par le caractère '\0'. Une telle chaîne peut se définir à l'aide des doubles guillemets.

  1. Implémenter l'instruction char mot[] = "Bonjour Toto!";. Combien de caractères contient cette chaîne ?
  2. Afficher cette chaîne à l'aide de printf.
  3. Remplacer le troisème o par un i à l'aide de l'instruction mot[9] = 'i'; (on observe qu'un char est défini à l'aide des simples guillemets). Afficher la chaîne.
  4. Remplacer le dernier o par un i. Afficher la chaîne.
  5. Remplacer le r par le caractère '\0'. Afficher la chaîne. Qu'observe-t-on ?
  6. Remplacer le j par le int 0. Afficher la chaîne. Qu'observe-t-on ?
  7. Afficher le code du char qui se trouve juste après le '!'.

13.2. Exercice 1301 - Afficher une chaine de caractères

Ecrire une fonction void afficher_chaine(char chaine[]) qui affiche à l'écran une chaîne de type C.

Indication: utiliser la fonction putchar.

13.3. Exercice 1302 - Afficher une chaine de caractères à l'envers

Ecrire une fonction void afficher_chaine_envers(char chaine[]) qui affiche à l'écran une chaîne de type C, à l'envers.

Indication: utiliser la fonction putchar.

13.4. Exercice 1303 - Palindrome

Ecrire une fonction int est_palindrome(char chaine[]) qui retourne 1 si la chaîne passée en paramètre est un palindrome et qui retourne 0 sinon.

13.5. Exercice 1305 - Longueur d'une chaîne de type C

Ecrire une fonction int longueur_chaine(char chaine[]) qui retourne la longueur de la chaîne de type C passée en paramètre.

13.6. Exercice 1306 - Longueur d'une chaîne de type C - Bis

Ecrire une fonction int longueur_chaine(char * chaine) qui retourne la longueur de la chaîne de type C passée en paramètre.

13.7. Exercice 1307 - Copier une chaîne de caractères

Ecrire une fonction void copier_chaine(char destination[], char source[]) qui copie la chaîne de caractère source dans la chaîne destination. Le caractère de fin de chaîne doit être pris en compte.

13.8. Exercice 1308 - Comparer deux chaînes de caractères

Ecrire une fonction int comparer_chaines(char chaine1[], char chaine2[]) qui retourne :

  • 0 si les deux chaînes sont égales
  • un nombre négatif si chaine1 est inférieure à chaine2 (dans l'ordre alphabétique)
  • un nombre positif si chaine1 est supérieure à chaine2 (dans l'ordre alphabétique)

On utilisera l'ordre alphabétique de cette table.

13.9. Exercice 1310 - Recherche de caractère dans une chaîne

Ecrire une fonction de prototype int position_char(char * chaine, char car) qui retourne :

  • la position du caractère car dans la chaîne chaine si car est présent dans la chaîne
  • -1 sinon

13.10. Exercice 1311 - Vérifier qu'une chaîne de caractères ne contient que des chiffres

Ecrire une fonction de prototype int seulement_chiffres(char * chaine), qui prend en paramètre une chaîne de caractères et qui retourne :

  • 1 si la chaîne ne contient que des chiffres
  • 0 sinon

13.11. Exercice 1312 - Convertir une chaîne contenant des chiffres en int

  1. Ecrire une fonction de prototype int chiffres_en_int(char * chaine) qui prend en paramètre une chaîne de caractères et qui :

    • vérifie que cette chaîne ne comporte que des chiffres (facultatif)
    • retourne un int correspondant à la valeur représentée par la chaîne

    Remarque : on ne s'intéresse qu'aux nombres positifs dans un premier temps.

  2. Prendre en compte les nombres négatifs.

13.12. Exercice 1315 - Conversion chaîne de caractère en chaîne de codes ascii

  1. Ecrire une fonction qui transforme une chaîne de caractères en la chaîne de caractères obtenue en concaténant les codes ascii en base 10 (sous forme de chaînes de caractères) de chacun des caractères de la chaîne de départ.

    Par exemple pour l'entrée

    "Bonjour! 2 + 2 = 4."
    

    on obtient la sortie

    66111110106111117114333250324332503261325246
    
  2. Ecrire une fonction qui fais la même chose que la fonction précédente mais avec les codes ascii représentés à l'aide de deux chiffres en hexadécimal.

    Par exemple pour l'entrée

    "Bonjour! 2 + 2 = 4."
    

    on obtient la sortie

    426F6E6A6F7572212032202B2032203D20342E
    

13.13. Exercice 1320 - Conversion d'une chaîne de codes ascii en chaîne de caractères

Ecrire une fonction qui transforme une chaîne composée d'une suite de codes ascii en une chaîne de caractères "standard".

Par exemple pour l'entrée

66111110106111117114333250324332503261325246

on obtient la sortie

"Bonjour! 2 + 2 = 4."

On pourra supposer que tous les codes figurant dans la chaîne de départ sont compris entre 20 et 199.

13.14. Exercice 1325 - Conversion d'une chaîne de codes ascii hexadécimaux

Ecrire une fonction qui transforme une chaîne composée d'une suite de codes ascii en hexadécimal en une chaîne de caractères "standard".

Par exemple pour l'entrée

426F6E6A6F7572212032202B2032203D20342E

on obtient la sortie

"Bonjour! 2 + 2 = 4."

13.15. Exercice 1330 - Conversion d'une chaine de caractères en suite de bits

  1. Ecrire une fonction qui transforme une chaîne de caractères en la chaîne de caractères obtenue en concaténant les codes ascii en base 2 (sous forme de chaînes de caractères) de chacun des caractères de la chaîne de départ.

    Par exemple pour l'entrée

    "Hi! 2+2=4."
    

    on obtient la sortie

    01001000011010010010000100100000001100100010101100110010001111010011010000101110
    
  2. Ecrire la fonction "réciproque", qui reconstruit la chaîne initiale depuis la suite de '0' et de '1'.

13.16. Exercice 1335 - Recherche de chaîne de caractères

Ecrire une fonction de prototype int souschaine(char * chaine1, char * chaine2) qui retourne -1 si chaine2 n'est pas une sous-chaîne de chaine1 et la position de chaine2 dans chaine1 sinon.

13.17. Exercice 1340 - Mélanger deux chaînes de caractères

Ecrire une fonction de prototype void melanger_chaines(char * cible, char * chaine1, char * chaine2) qui construit une chaine en prenant le premier caractère de chaine1, le premier caractère de chaine2, puis le deuximème caractère de chaine1, le deuxième de chaine2, etc… Si tous les caractères d'une des deux chaînes ont été épuisés, on complète la cible à avec les caractères restants dans l'autre chaîne.

Par exemple, le code :

int main()
{
    char chaine1[] = "abcdefghijklmnop";
    char chaine2[] = "ABCDEFGH";
    char cible[500] = {};
    melanger_chaines(cible, chaine1, chaine2);
    printf("%s\n", cible);
    return 0;
}

produit la sortie :

aAbBcCdDeEfFgGhHijklmnop

13.18. Exercice 1350 - Compter un caractère donné dans une chaine   chaine analyser compter caractere

Ecrire une fonction de prototype int compter_caractere(char * src, char car) qui compte le nombre de fois que le caractère car est présent dans la chaîne src.

Vous pouvez tester votre fonction sur la chaîne

char test[] = "ALFA ROMEO ;159 ;ALFA ROMEO ;159 ;159 1750 Tbi (200ch) ;M10ALFVP000G340 ;939AXN1B52C ;ES ;non ;12;147;;M 6 ;11.3;5.8;7.8;182;0.647;0.052;0.032;;0.002;1505;1505;715/2007*692/2008EURO5 ;juin-14";

qui contient 25 caractères ;.

13.19. Exercice 1360 -   chaine analyser compter caractere

  1. Ecrire une fonction de prototype int extraire_morceau(char * src, char * dest, int debut, char sep) qui :

    1. recopie la sous-chaine de src comprise entre l'indice debut et l'indice du premier caractère sep positionner après start
    2. retoure la position caractère se trouvant juste après le sep trouvé

    Par exemple le le morceau de code suivant :

    char test[] = "ALFA ROMEO ;159 ;ALFA ROMEO ;159 ;159 1750 Tbi (200ch) ;M10ALFVP000G340 ;939AXN1B52C ;ES ;non ;12;147;;M 6 ;11.3;5.8;7.8;182;0.647;0.052;0.032;;0.002;1505;1505;715/2007*692/2008EURO5 ;juin-14";
    char dest[100];
    int debut = 0;
    int nouveau_debut;
    
    nouveau_debut = extraire_morceau(test, dest, debut, ';');
    printf("%d, %d\n", debut, nouveau_debut);
    printf(dest);
    

    affiche à l'écran :

    0, 12
    ALFA ROMEO 
    
  2. Ecrire une boucle qui permette d'afficher la sortie suivante :

         0, ALFA ROMEO
        12, 159
        17, ALFA ROMEO
        29, 159
        34, 159 1750 Tbi (200ch)
        56, M10ALFVP000G340
        73, 939AXN1B52C
        86, ES
        90, non
        95, 12
        98, 147
    102,
    103, M 6
    108, 11.3
    113, 5.8
    117, 7.8
    121, 182
    125, 0.647
    131, 0.052
    137, 0.032
    143,
    144, 0.002
    150, 1505
    155, 1505
    160, 715/2007*692/2008EURO5
    184, juin-14
    

14. Communication avec l'environnement

14.1. Exercice 1400 - Une autre signature pour la fonction main

On donne le code ci-dessous :

#include <stdio.h>

int main(int argc, char* argv[])
{
    return 0;
}
  1. Le code ci-dessus compile-t-il sans erreur ?
  2. Observer la signature de la fonction main. Quel est le type de argc ?
  3. Afficher la variable argc. Quelle valeur contient-elle ?
  4. Quel est le type de argv ?
  5. Afficher argv[0]. Quelle valeur obtient-on ?

14.2. Exercice 1402 - Passer des paramètres au programme

Ecrire un programme arg.exe qui, lorsqu'il est appelé comme cela :

./arg.exe toto titi tutu

produit la sortie :

Nombre d'arguments : 4
L'argument 0 est : ./arg.exe
L'argument 1 est : toto
L'argument 2 est : titi
L'argument 3 est : tutu

14.3. Exercice 1405 - Un programme pour les additionner des chiffres

Produire un programme addition_chiffres.exe qui, lorsqu'il est appelé comme cela :

./addition_chiffres.exe 3 9

produit la sortie :

Somme = 12

14.4. Exercice 1406 - Une première calculatrice

Produire un programme operation.exe qui, lorsqu'il est appelé comme cela :

./operation.exe 3 9 +

produit la sortie :

12

et comme ceci :

./operation.exe 60 18 -

produit la sortie :

-42

Les symboles autorisés pour le troisième argument sont '+', '-', '*' et '/'.

Remarques :

  • Cet exercice requiert une fonction pour convertir une chaîne de caractères contenant des chiffres en int.
  • Que se passe-t-il pour l'opération '*'.

14.5. Exercice 1408 - Une calculatrice complète en notation polonaise inverse

Produire un programme calc.exe qui, lorsqu'il est appelé comme cela :

./calc.exe 10 2 4 x 3 + x

produit la sortie :

110

et comme ceci :

./calc.exe 5 2 x 3 4 x +

produit la sortie :

22

14.6. Exercice 1410 - Nombre de caractères

Ecrire un programme qui compte le nombre de caractère d'un fichier passé en paramètre.

14.7. Exercice 1415 - malloc   signature malloc

  1. A l'aide de la fonction sizeof aficher la taille du type void. Que signifie void?

La fonction malloc (raccourci pour memory allocation) permet d'allouer dynamiquement de la mémoire vive à un programme.

  1. En effectuant un appel à la fonction malloc et en utilisant les messages fournis par le compilateur, deviner :
    1. Le nombre et le type de paramètres requis par la fonction malloc.
    2. Le fichier .h dans lequel est défini malloc.
  2. En stockant le résultat renvoyé par malloc dans une variable adr, et en utilisant les messages fournis par le compilateur, deviner le type de retour de la fonction malloc.
  3. Allouer 100 Mo de mémoire vive.
  4. Afin d'empêcher la fermeture instantanée du programme, faire un appel à getchar juste avant le return du main.
  5. Ouvrir le gestionnaire des tâches (pour Windows, top pour linux, activity monitor pour mac), lancer le programme, puis rechercher ce même programme dans la liste des processus. Qu'observe-t-on ?
  6. A l'aide d'une boucle for stocker une valeur dans chacun des octets alloués à la question 4. Qu'observe-t-on dans le gestionnaire de tâches ?
  7. Qu'observe-t-on alors dans le gestionaire de tâches ?
  8. Libérer la mémoire allouée à l'aide de la fonction free, après l'appel à getchar.
  9. Afin d'avoir le temps d'observer la libération de mémoire, appeler une seconde fois getchar après l'appel à free.

14.8. Exercice 1416 - malloc 2   malloc

  1. Demander à l'utilisateur combien d'octets il souhaite allouer (en Mo).
  2. Recueillir la réponse à l'aide de scanf.
  3. Allouer effectivement la mémoire et y stocker des 0.
  4. Tester si l'allocation a bien fonctionné.
  5. Tant que la quantité souhaitée est non nulle, recommencer 1., 2., 3. et 4. (utiliser une boucle while).
  6. Exécuter le programme tout en observant le gestionnaire de tâches.
  7. Comment libérer proprement la mémoire ?
  8. Imaginer un programme malveillant qui sature la mémoire de l'hôte.

14.9. Exercice 1420 - Allocation dynamique de mémoire et tableau   allocation dynamique

Cette exercice peut utiliser fonctions_utiles.h.

Ecrire un programme qui :

  1. demande à un utilisateur d'entrer un nombre \(n\)
  2. alloue dynamiquement la mémoire nécessaire pour stocker \(n\) double dans un entier
  3. demande à l'utilisateur de saisir \(n\) valeurs réelles
  4. stocke chacune de ces valeurs dans la mémoire précedemment allouée
  5. affiche le tableau
  6. libère la mémoire allouée

14.10. Exercice 1430 - Allocation de mémoire et tableau 2d

Ecrire un programme qui :

  • demande à l'utilisateur un nombre n de lignes à saisir
  • alloue la mémoire nécessaire pour stocker n variables de type char *
  • demande à l'utilisateur de taper n phrases
  • à chaque phrase alloue la mémoire nécessaire pour stocker cette phrase; le pointeur renvoyé par malloc lors de la ième allocation est stocké dans la ième case du tableau de char * ci-dessus
  • enregistre chacune des phrases au bon endroit
  • affiche les n phrases en colonne (voir exemple ci-dessous)
  • libère convenablement la mémoire allouée

Un exemple d'exécution pourrait être :

Nombre de lignes :3
Bonjour Toto
Hi Titi
Guten Tag Titi
BHG
oiu
n t
jTe
oin
ut
riT
  a
T g
o
t T
o i
  t
  i

15. Opérations sur les bits

15.1. Exercice 1500 - Opérateurs bit à bit (bitwise operator)

  1. Déclarer deux variables n et p de type int, respectivement initialisées à 170 et à 27.
  2. Afficher (%u de préférence) les valeurs auxquelles sont évaluées les expressions :

    • n&p
    • n|p
    • n^p
    • ~n
    • ~p

    Qu'observe-t-on ?

  3. Donner les expressions binaires de tous les nombres qui interviennent ci-dessus. Qu'observe-t-on ?

15.2. Exercice 1510 - Le dernier bit à 0

Ecrire une fonction de prototype int dernierBitAZero(int entier). Cette fonction doit mettre le bit de poids faible de entier à 0.

15.3. Exercice 1520 - Le dernier bit à 1

Ecrire une fonction de prototype int dernierBitAUn(int entier). Cette fonction doit mettre le bit de poids faible de entier à 0.

15.4. Exercice 1530 - Bit shifts

  1. Initialiser une variable n de type int à 1.
  2. Afficher les valeurs prises par les expressions n << 1, n << 2, n << 8, n << 9, n << 16. Qu'observe-t-on ?
  3. Recommencer avec d'autres valeurs de n.

15.5. Exercice 1535 - Représentation binaire d'un int   shift masque representation binaire

  1. Implémenter une fonction void binaryPrintf(int n) qui affiche les 32 bits de la représentation binaire du int passé en paramètre. La fonction doit utiliser les bitwise shifts.
  2. Que faire si on se trouve sur une architecture où les int ne sont pas codés sur 32 bits ?

Indication: si vous utilisez un masque, choisissez le de type unisgned int (pourquoi?).

15.6. Exercice 1540 - Boutisme (Endianness)   boutisme conversion pointeurs

Ecrire un programme qui déclare un int à la valeur 1416590447. Interpréter cet int comme un tableau de caractères que l'on affichera.

Quel mot découvre-t-on ?

Remarque : on réimplémentera ou réutilisera la fonction void afficher_tab_char(char tab[], int taille).

16. Structures

16.1. Exercice 1600 - Première structure   structures sizeof struct

On considère le code ci-après :

#include <stdio.h>

struct point
{
    double abs; /* l'abscisse du point */
    double ord; /* l'ordonnee du point */

}; /* attention au point virgule */

int main()
{
    struct point mon_point;
    struct point mon_deuxieme_point = {-3.5, 6.8};

    mon_point.abs = 2.3; /* initialisation de l'abscisse de point */
    mon_point.ord = 3.7; /* initialisation de l'ordonnee de point */

    return 0;
}
  1. Tester le code ci-dessus. Ce propose la modélisation d'un point du plan à l'aide d'une structure.
  2. Afficher l'abscisse et l'ordonnée des deux points.
  3. Afficher, à l'aide de sizeof, la taille occupée en mémoire par la structure point.

16.2. Exercice 1605 - Poursuivre la familiarisation avec les structures   structures tableau

  1. Reprendre la structure struct point de l'exercice 1600.
  2. Déclarer un tableau de 4 points.
  3. Initialiser les points du tableaux de sorte qu'ils forment un carré.
  4. Afficher les points du tableaux sont la forme {(x1,y1),(x2,y2),(x3,y3),(x4,y4)}.
  5. Copier-coller le résultat de la question précédente dans https://www.geogebra.org. Obtient-on bien un carré ?
  6. Comment déterminer le centre du carré ?

16.3. Exercice 1610 - Quelques fonctions pour les points   sruct fonctions

Cet exercice utilise la structure point.

  1. Ecrire et tester une fonction de prototype double distance_carree(struct point p1, struct point p2) qui retourne le carré de la distance euclidienne entre les points p1 et p2.
  2. Ecrire une fonction de prototype double distance(struct point p1, struct point p2) qui retourne la distance euclidienne entre les points p1 et p2.

16.4. Exercice 1615 - Approximation de pi à l'aide de points   struct point monte carlo

Cet exercice utilise la structure point.

  1. Déclarer un tableau de 1000 point.
  2. Initialiser aléatoirement et uniformément sur \([0;1]\) les abscisses et les ordonnées de ces points. On pourra utiliser les fonctions rand et srand de stdlib.h.
  3. Compter les points qui sont à une distance au point \((0.5,0.5)\) inférieure à 0.5.
  4. Rappeler la formule qui donne l'aire d'un disque.
  5. Déduire de 3. et de 4. une approximation de \(\pi\).
  6. Recommencer avec un plus grand nombre de points.
  7. Commenter.

16.5. Exercice 1630 - Structure et modularité

Ecrire un fichier geometrie.h qui contient la structure point précédemment introduite.

16.6. Exercice 1635 - Un alias pour les points   typedef alias structure

  1. Regrouper dans un même fichier :
    • la structure représentant un point (struct point)
    • la fonction distance_carree
    • la fonction distance
  2. Déclarer trois points A, B et C. Initialiser ces points de trois manières différentes.

Il est pénible de taper struct point à chaque fois que l'on souhaite manipuler une variable représentant un point. Le C permet de donner un surnom (ou alias) à un type de donnée. Il faut pour cela utiliser le mot-clef typedef.

  1. Donner l'alias Point au type de donnée struct point à l'aide de l'instruction

    typedef struct point Point.

  2. Déclarer un nouveau point D à l'aide de l'alias Point.
  3. Peut-on utiliser la fonction distance avec le point D ?
  4. Utiliser l'alias Point dans le prototype de la fonction distance.

16.7. Exercice 1640 - Une structure en paramètre de fonction   struct fonctions parametre

Ecrire une fonction de prototype void set_abs(struct point * p, double nouvelle_abs) qui met à jour l'abscisse du point passé en paramètre.

Pourquoi utiliser un pointeur ?

Ecrire de même la fonction void set_ord(struct point * p, double nouvelle_ord).

16.8. Exercice 1650 - Une structure contenant un tableau   struct fonctions parametre valeur

Exécutez le code ci-après et commentez les différentes adresses mémoire observées.

Que se passe-t-il au niveau des adresses mémoire si on utilise un tableau de 48 char au lieu de 50 char pour le nom ?

#include <stdio.h>
#include <string.h>

struct Bonhomme {
    char nom[50];
    int age;
};

void modifier_bonhomme(struct Bonhomme b)
{
    printf("adr b : %p, adr b.nom %p, adr b.age : %p (dans la fonction)\n", &b, &b.nom, &b.age);
    strcpy(b.nom, "Titi");
    b.age = 42;
}

int main(int argc, char* argv[])
{
    struct Bonhomme monBonhomme = {"Toto", 23};
    printf("adr monBonhomme : %p, adr monBonhomme.nom : %p, adr monBonhomme.age : %p\n",
           &monBonhomme, &monBonhomme.nom, &monBonhomme.age);
    printf("nom : %s, age : %d\n", monBonhomme.nom, monBonhomme.age);
    modifier_bonhomme(monBonhomme);
    printf("adr monBonhomme : %p, adr monBonhomme.nom : %p, adr monBonhomme.age : %p\n",
           &monBonhomme, &monBonhomme.nom, &monBonhomme.age);
    printf("nom : %s, age : %d\n", monBonhomme.nom, monBonhomme.age);

    return 0;
}

16.9. Exercice 1660 - Une structure pour les nombres complexes   struct fonctions

  1. Ecrire une structure struct complexe permettant de représenter un nombre complexe. Cette structure doit disposer d'un champs re de type double et d'un champ im de type double.
  2. Ecrire une fonction double module(struct complexe z) qui retourne le module du nombre complexe.
  3. Ecrire une fonction double argument(struct complexe z) qui retourne l'argument (dans \(]-\pi;\pi]\)) de z. On pourra utiliser la formule \(\text{arg}(z=x+iy)=2\arctan\left(\frac{y}{\sqrt{x^{2}+y^{2}}+x}\right)\) lorque \(z\) n'est pas un réel négatif ou nul.
  4. Ecrire une fonction void afficher_complexe(struct complexe z) qui affiche z sous la forme "partie rélle + partie imaginaire fois i". Par exemple, si

    struct complexe z = {1, 2};

    alors l'appel à la fonction afficher_complexe(z) affiche :

    1+2i

  5. Ecrire une fonction void modifier_re(struc complexe * z, double nouveau_re) qui modifie la partie réelle du nombre complexe dont l'adresse est passée en paramètre. Par exemple, le code :

    struct complexe z = {2, -3.5};
    afficher_complexe(z);
    modifier_re(&z, 42);
    afficher_complexe(z);
    

    produit la sortie :

    2+-3.5i
    2+42i
    
  6. Ecrire une fonction analogue pour la partie imaginaire.
  7. Améliorer la fonction afficher_complexe pour tenir compte d'une partie réelle ou imagine nulle ou négative.

17. Structures de données

17.1. Exercice 1700 - Une structure pour les triangles   structures typedef alias tableaux

  1. Implémenter une structure de données struct point permettant de modéliser un point du plan.
  2. Déclarer et initialiser 3 points A, B et C, en utilisant trois manières différentes.
  3. En utilisant le mot réservé typedef donner l'alias (le surnom) Point à la structure précédemment définie.
  4. Déclarer et initialiser un point E et un point F à l'aide de cet alias.
  5. Implémenter une fonction de signature float longueur(Point A, Point B) qui calcule la longueur entre deux points. Tester cette fonction.

On souhaite désormais représenter un triangle à l'aide d'un tableau de type Point [].

  1. Déclarer est initialiser un tableau t1 contenant trois Point.
  2. Implémenter une fonction de prototype float perimetre(Point t[]). Tester.
  3. Implémenter une fonction void afficher_tr(Point tr[]).
  4. Comment translater un point ? Un triangle ?

17.2. Exercice 1730 - Vers les listes simplement chaînées   liste structures

17.2.1. Première partie

Une liste simplement chaînée est une structure de donnée dynamique permettant de stocker un nombre (variable) de valeurs, que l'on peut représenter comme suit :

tete
 |
 v
+----------+   +----------+   +----------+
|      |   |   |      |   |   |      |   |
| 45   | ----->| 97   | ----->| -3   | -----> ∅
|      |   |   |      |   |   |      |   |
+----------+   +----------+   +----------+
  • 45, 97 et -3 sont les trois valeurs stockées dans la liste
  • une flèche indique l'emplacement de l'élément suivant

Le but de l'exercice est de se familiariser avec certaines notions préalables à l'implémentation de cette structure. Un élément de la liste est constitué d'une valeur et d'une flèche (qui est l'adresse de l'élément suivant).

+-----------+              +---------------------+
|      |    |              |        | adresse de |
| 97   | ------>   <=>     | valeur | l'élément  |
|      |    |              |        | suivant    |
+-----------+              +---------------------+
  1. Implémenter, à l'aide du mot réservé struct une structure représentant un élément de la liste.
  2. A l'aide de typedef, surnommer (alias) Element cette structure.
  3. Déclarer trois Elements nommé premier, deuxieme et troisieme.
  4. Faire en sorte que premier stocke la valeur 45, que deuxieme stocke la valeur 97 et que troisieme stocke la valeur -3.
  5. Afficher la valeur stockée dans premier.
  6. Faire en sotre que l'adresse du suivant de premier soit l'adresse de deuxieme.
  7. Faire en sotre que l'adresse du suivant de deuxieme soit l'adresse de troisieme.
  8. Quelle doit être l'adresse du suivant de troisieme ?
  9. En utilisant la variable premier afficher la valeur stockée dans deuxieme.
  10. En utilisant la variable premier afficher la valeur stockée dans troisieme.
  11. Implémenter une fonction de prototype void afficher(Element * adr_el) de telle sorte que l'appel

    afficher(&premier)

    produise une sortie ressemblant à :

    45 à l'adresse 0x7ffe8840b760
    97 à l'adresse 0x7ffe8840b750
    -3 à l'adresse 0x7ffe8840b740
    
  12. Implémenter une fonction de prototype int longueur(Element * adr_el) permettant de calculer la longueur de la liste commençant à l'élément d'adresse adr_el. Tester.

17.2.2. Deuxième partie

On aimerait pouvoir ajouter un quatrième élément à la liste, lors de l'exécution du programme.

  1. Reprise. Déclarer un Element nommé quatrieme et qui contient la valeur 23.
  2. "Accrocher" cet élément à la fin de la liste.
  3. A l'aide de scanf demander à l'utilisateur s'il souhaite ajouter une valeur à la liste. Si oui, lui demander quelle valeur il souhaite ajouter et stocker cette valeur dans une variable tmp. Sinon, le programme s'arrête.
  4. Afficher la valeur que l'utilisateur à saisie. Pour l'instant cette valeur n'est pas encore ajoutée à la liste.
  5. Déclarer une variable adr_cinquieme. Quel est le type de cette variable?
  6. A l'aide de malloc allouer la mémoire permettant de stocker un Element supplémentaire. Affecter l'adresse retournée par malloc dans adr_cinquieme.
  7. Stocker la valeur tmp dans adr_cinquieme->valeur.
  8. Faire en sorte que l'adresse du suivant du cinquième élément soit NULL.
  9. Afficher à nouveau la liste à l'aide de afficher.
  10. Observer l'adresse de l'élément ajouté à l'exécution du programme. Que constate-t-on ?
  11. Libérer la mémoire allouée pour le cinquième élément.

17.2.3. Troisième partie

  1. Implémenter une fonction de prototype Element * adr_dernier(Element * adr_el) qui prend en parammètre l'adresse d'un élément et qui retourne l'adresse du dernier élément de la liste qui commence par l'élément d'adresse adr_el. Que faire si adr_el est NULL ?
  2. Implémenter une fonction de prototype ajouter_valeur(Element * adr_el, int val) qui ajoute dynamiquement (malloc) la valeur val à la liste dont le premier élément a pour adresse adr_el. On suppose que l'élément à l'adresse adr_el existe (c'est-à-dire que la liste n'est pas vide). Quel est le problème si la liste est vide ?
  3. Implémenter une fonction de prototype liberer_memoire(Element * adr_el) qui libère la mémoire allouée aux élements suivants l'élément d'adresse adr_el.
  4. Quel est le problème avec les listes vides ? Que se passe-t-il si on ajoute un élément à l'adresse NULL par exemple ?

18. Rétro-ingénierie

18.1. Exercice 1800   retro

On cherche une fonction f telle que les appels

f("72101108108111328711111410810033")
f("8511032112101117321001013211410111611411145105110103101110105101114105101")
f("851103211611411110511510510110910132101120101109112108101")

retournent respectivement

"Hello World!"
"Un peu de retro-ingenierie"
"Un troisieme exemple"
  1. Implémenter f.
  2. Que vaut f("66111110106111117114326710497116718084")?

18.2. Exercice 1810   retro

Appels:

f('A')
f('a')
f('1')
f('2')

Affichage:

1010
1010
1
10
  1. f('b').
  2. f('9').

18.3. Exercice 1820   retro

Appels:

f(42)
f(17)
f(255)
f(1)

Valeurs retournées:

3
2
8
1

19. Hasard

19.1. Exercice 1900 - Les fonctions rand et srand   aleas rand srand

  1. Inclure la librairie stdlib.h.
  2. Afficher le résultat d'un appel à la fonction rand.
  3. Afficher 20 nombres aléatoires à l'aide d'une boucle.
  4. Exécuter plusieurs fois le programme. Que constate-t-on ?
  5. Appeler la fonction srand une fois avant le premier appel à rand.
  6. Modifier la valeur du paramètre de srand.
  7. Inclure la librairie time.h.
  8. Afficher le résultat de l'appel time(NULL). Exécuter plusieurs fois le programme.
  9. Utiliser la fonction time pour faire un appel à srand différent à chaque exécution du programme.

19.2. Exercice 1910 - Loi uniforme sur un intervalle   loi uniforme aleas rand

  1. Afficher la valeur maximale que la fonction rand puisse retourner (cette valeur est contenu dans la variable RAND_MAX de la librairie stdlib.h).
  2. Ecrire une fonction de prototype double loi_uniforme(double a, double b) qui retourne un nombre réel aléatoire compris entre les réels a et b.
  3. Tester la fonction loi_uniforme.

20. Le préprocesseur

20.1. Exercice 2000

  1. Produire un fichier exo2000.c contenant exactement le code source suivant :
int main() {
    return 0;
}
  1. Compiler ce programme en utilisant l'option E du compilateur : gcc -E exo2000.c. Que se passe-t-il ? Le programme est-il vraiment compilé ?
  2. Ajouter la directice #include <stdio.h> au début du fichiet et recommencer l'étape de la question précédente. Qu'observe-t-on ?
  3. Ajouter la directive #define TOTO 42 juste après la directive #define précédente et recompiler avec l'option E. Qu'obeserve-t-on ?

21. Approfondissement

21.1. Exercice 10000 - Un échange astucieux

Trouver un moyen d'échanger le contenu de deux variables sans avoir recours à une variable auxiliaire.

21.2. Exercice 10005 - Allocation dynamique et typage

  1. Déclarer une variable char * tab.
  2. Allouer un tableau de 2 char à l'adresse tab.
  3. Affecter la valeur 0 à l'adress tab et 1 à l'adresse tab+1.
  4. Afficher ce qui se trouve à l'adresse tab après l'avoir converti en short int *.
  5. Expliquer le résultat obtenu.
  6. Libérer la mémoire allouée.

21.3. Exercice 10010 - Représentation binaire   representation binaire bitshift boucles

Ecrire une fonction qui prend en paramètres un unsigned char et un char *. Le paramètre de type char * pointe vers un tableau de char permettant de stocker une chaîne de 8 catactères. La fonction doit établir la représentation binaire du paramètre de type unsigned char dans le tableau pointé par le deuxième paramètre.

21.4. Exercice 10015 - Depuis la représentaton binaire

Ecrire une fonction qui prend en paramètre une chaîne de 8 caractère composée de '0' et de '1' et qui retourne le unsigned char correspondant.

21.5. Exercice 10020 - Conversion de pointeur

  1. Vérifier que sur votre environnment, un long int est codé sur 8 octets.
  2. Déclarer une variable n de type long int.

On souhaite que l'exécution des lignes de code suivantes :

char * tab = (char*)&n;
int i;
for(i=0;i<8;i++)
{
    putchar(*(tab+i));
}

produise l'affichage :

Bonjour!
  1. A quelle valeur entière faut-il initialiser n pour obtenir ce résulat ?

21.6. Exercice 10025 - Distance à l'origine

Requiert geometrie.h.

  1. Dans un fichier geometrie.c, écrire une fonction de prototype double distance_carre(struct point p) qui calcule le carré de la distance euclidienne entre l'origine et le point p.
  2. Placer le prototype de la fonction dans geometrie.h.

21.7. Exercice 10030 - Stéganographie

Pré-requis : ** Exercice 1250 - Lire un fichier en mode binaire

L'image paysage.bmp dissimule une information codée. Chaque pixel de cette image dispose d'une couleur déterminée par un triplet d'entiers noté (b,g,r), pour (blue, green, red). Chacune des trois valeurs est comprise entre 0 et 255. Par exemple (0,255,0) représente le vert "pur".

Un changement "de 1" dans la valeur d'une des couleurs est imperceptible à l'oeil nu. Par exemple, (123, 48, 84) et (122, 48, 84) représente deux couleurs quasiment indistingables. On peut alors modifier la parité de b, de g ou de r pour dissimuler de l'information. Dans cette exercice une image en noir et blanc à été codée dans la quantité de bleu (b) de l'image ci-dessus. Un pixel avec un b impair correspond à un pixel noir dans l'image codée tandis qu'un b pair correspond à un pixel blanc.

L'exercice consite à écrire un programme qui produit un fichier image_decodee.bmp.

21.8. Exercice 10035 - Chiffrement par décalage

Implémenter une fonction de prototype

void chiffrement_decalage(char * source, char * cible, char * alphabet, int longueur_alphabet, int decalage)

qui chiffre par décalage la chaîne de caractères source a l'aide de l'aphabet alphabet avec un décalage de decalage. La chaîne chiffrée est stockée à l'adresse cible. La longueur de l'alphabet est passée en paramètre.

Par exemple, si source="bonjour le monde", alphabet="abcdefghijklmnopqrstuvwxyz ", decalage=5, alors cible="gtsotzweqjertsij".

21.9. Exercice 10040 - Déchiffrement par décalage

Implémenter une fonction de prototype

void dechiffrement_decalage(char * source, char * cible, char * alphabet, int longueur_alphabet, int decalage)

qui déchiffre une chaîne de caractères chiffrée par la fonction

void chiffrement_decalage(char * source, char * cible, char * alphabet, int longueur_alphabet, int decalage)

précedemment codée.

21.10. Exercice 10045 - PCR   boucle recurrence

Lors d'une réction de polymérase en chaîne (PCR) les quantités suivantes interviennent:

\(A_{n}\): quantité de brins d'ADN natif sens

\(B_{n}\): quantité de brins d'ADN antisens bien défini à l'extrémité 5' correspondants à l'amplicon

\(C_{n}\): quantite de brins d'ADN sens bien définis aux deux extrêmités correspondants à l'amplicon

\(D_{n}\): quantite de brins d'ADN antisens bien définis aux deux extrêmités correspondants à l'amplicon

\(E_{n}\): quantité de brins d'ADN sens bien défini à l'extrémité 5' correspondants à l'amplicon

\(F_{n}\): quantité de brins d'ADN natif antisens

A chaque cycle ces grandeurs sont liées par les relations :

\(\begin{cases}A_{n+1}=A_{n}\\B_{n+1}=B_{n}+A_{n}\\C_{n+1}=C_{n}+B_{n}+D_{n}\\D_{n+1}=D_{n}+E_{n}+C_{n}\\E_{n+1}=E_{n}+F_{n}\\F_{n+1}=F_{n}\end{cases}\)

On suppose que \(A_{0}=F_{0}=1\) et \(B_{0}=C_{0}=D_{0}=E_{0}\).

Ecrire un programme qui donne les quantités des différents constituants pour les vingt premiers cycles.

21.11. Exercice 10050 - Devinette

Ecrire un programme qui demande à l'utilisateur de devinez un nombre préalablement tiré au hasard entre 0 et 100. A chaque tour, le programme doit indiquer à l'utilisateur s'il a trouvé le bon nombre. Sinon le programme indique si le nombre proposé est plus grand ou plus petit que le nombre recherché. L'utilisateur à un nombre d'essais fixé à l'avance.

21.12. Exercice 10060 - Exploiter de vraies données

  1. Télécharger le fichier fic_etiq_edition_40-mars-2015.csv. Ce fichier provient du site https://www.data.gouv.fr/fr/datasets/emissions-de-co2-et-de-polluants-des-vehicules-commercialises-en-france/ et servira de prétexte à la manipulation de données réelles.
  2. Ouvrir le fichier à l'aide d'un tableur et examiner le. Combien y-a-t-il de colonnes ? A quoi sert la premiere ligne?
  3. Ouvrir le ficher avec un éditeur de texte. Quel caractère est utilisé pour séparer deux colonnes ?

On aimerait exploiter les données à l'aide d'un programme informatique. On va représenter les données de ce tableau à l'aide d'une structure :

struct vehicule {
    char lib_mrq_doss[30];
    char lib_mod_doss[30];
    char mrq_utac[20];
    char mod_utac[20];
    char dscom[50];
    char cnit[30];
    char tvv[20];
    char energ[20];
    char hybride[10];
    int puiss_admin;
    int puiss_max;
    int puiss_heure;
    char typ_boite_nb_rapp[10];
    float conso_urb_93;
    float conso_exurb;
    float conso_mixte;
    int co2_mixte;
    float co_typ_1;
    float hc;
    float nox;
    float hcnox;
    float ptcl;
    int masse_ordma_min;
    int masse_ordma_max;
    char champ_v9[20];
    char date_maj[20];
};
  1. Ecrire un programme permettant de stocker chacun des véhicules du fichier en mémoire, à l'aide de la structure ci-dessus.

21.13. Exercice 10070 - Type punning 1   pointeurs type conversion

Le but de cet exercice est de stocker un nombre réel (a priori de type float) dans une variable de type uint32_t, sans perdre de précision.

  1. Vérifier qu'un float est qu'un uint32_t occupent la même place en mémoire.
  2. Vérifier que deux conversions consécutives, comme (float)(uint32_t)x perd de l'information.
  3. Déclarer une variable m de type unint32_t et une variable y de type float.
  4. Dans la variable m, déréférencer l'adresse de x, préalablement convertie en uint32_t*. Afficher le contenu de m.
  5. Dans la variable y, déréférencer l'adresse de m, préalablement convertie en float*. Afficher le contenu de y.

21.14. Exercice 10080 - Type punning 2   pointeurs type conversion

  1. Déclarer une variable n de type uint32_t contenant la valeur 1078530011. Cette valeur correspond à une suite de 32 bits en mémoire.
  2. Quel est le float (en norme IEEE 754) représenté par cette suite de bits ?

21.15. Exercice 10090 - Norme IEEE 754   type memcopy

  1. Déclarer une variable n de type int et une variable x, de type float.
  2. Affecter la valeur 1078530011 à n.
  3. A l'aide de la fonction memcopy de la librairie string.h copier les octets se situant à l'adresse &n à l'adresse &x.
  4. Afficher x. Quelle valeut opbtient-on ?