Support de cours d'introduction à la programmation en langage C

Table des matières

1 À propos

Ce support de cours est destiné, en priorité, aux élèves du BTS Systèmes numériques au Lycée Sainte Famille Saintonge à Bordeaux. Toutefois, il peut être utile à toute personne intéressée combien même cette dernière n'aurait jamais fait de la programmation au préalable, que ce soit en utilisant le langage C ou tout autre langage de programmation.

L'objectif est, dans un premier temps, de clarifier les enjeux de la programmation en tant que telle, sans se focaliser sur un langage de programmation en particulier. En mettant en avant la notion d'algorithme, nous allons expliquer les principes d'un langage de programmation en général pour finalement introduire le langage C et ce notamment à travers des exercices permettant de mettre en pratique les notions vues en cours. Un corrigé avec explication détaillée est proposé pour tous les exercices dans ce support.

1.1 Contacter l'auteur

Toute incohérence, erreur, propositions d'amélioration ou d'extension peut être adressée à l'auteur par courriel via marek.felsoci@inria.fr.

1.2 Condition d'usage et de distribution

Ce document est destiné exclusivement à l'usage académique ! Son contenu est mis à disposition selon les termes de la licence Creative Commons Attribution, pas d'utilisation commerciale et partage dans les mêmes conditions 4.0 International. Pour consulter le texte intégral de la licence, veuillez suivre ce lien.

2 Programmation

Imaginons une personne qui n'a jamais fait de cuisine et que l'on lui demande de préparer un gâteau sans lui expliquer comment faire. Elle ne saurait par où commencer. Il faut absolument lui indiquer la marche à suivre. Il en est tout autant dans le cas d'un ordinateur. Sans un logiciel programmé pour piloter ce dernier, seul le matériel ne nous aiderait pas à retoucher une photographie, visionner une vidéo ou encore comparer une empreinte digitale.

Revenons en encore à notre exemple de cuisine. Il ne suffit pas de fournir à la personne en question une recette, d'autant plus si cette dernière est écrite par un cuisinier expérimenté. Sans aucune expérience préalable, la personne ne serait pas beaucoup plus avancée, même en disposant de la recette.

Analysons l'extrait suivant d'une recette de cuisine : « […] Dans un Wok faites revenir dans de l'huile d'olive du blanc de poulet coupé en petits morceaux. Quand le poulet est cuit, […] » À un cuisinier qui s'y connaît en la matière, ces quelques instructions paraîtraient sans doute suffisamment claires pour qu'il sache ce qu'il doit faire. Ce n'est pas forcément le cas pour un débutant. Combien de temps faut-il pour faire cuire de la viande de poulet ? Comment sait-on que la viande est déjà cuite ? Ou bien, qu'est-ce qu'un Wok ? Voici quelques questions qu'un débutant de cuisine pourrait se poser en lisant cette recette.

Les instructions doivent être décrites de manière compréhensible et dans un langage compréhensible au destinataire. Disons qu'écrites de la façon suivante, ces instructions pourraient paraître plus claires même pour un parfait amateur : « […] Dans une poêle creuse, faire chauffer de l'huile pendant 3 minutes à feu vif. Puis, disposer du blanc de poulet découpé en dés d'une taille approximative de 2 centimètres dans la poêle. Continuer à retourner les dés de manière régulière à l'aide d'une cuillère en bois jusqu'à ce que les morceaux de viande deviennent blancs à l'intérieur comme à l'extérieur. […] »

3 Algorithme

Un ordinateur lui aussi a besoin d'une « recette » écrite de façon à ce qu'il la comprenne et dans un langage qu'il est capable d'interpréter. En informatique, l'on appelle cette « recette » un algorithme.

Un algorithme se traduit par une suite d'instructions permettant de résoudre un problème ou bien effectuer un calcul donné. Ainsi, un algorithme n'est pas, dans un premier temps, nécessairement écrit dans un langage de programmation.

Prenons l'exemple suivant. Nous voulons fournir à un ordinateur un algorithme pour qu'il soit capable d'effectuer l'addition de deux nombres entiers quelconques, appelés opérandes. Dans Exemple 1, nous proposons un algorithme écrit en français, dans un premier temps, et mettant en avant une méthode pour résoudre ce problème énoncé dans un langage bien propre aux humains.

Définir trois valeurs entières variables, OPÉRANDE1, OPÉRANDE2 et RÉSULTAT.

Demander à l'utilisateur humain d'entrer une valeur entière et la stocker dans
OPÉRANDE1.

Demander à l'utilisateur humain d'entrer une valeur entière et la stocker dans
OPÉRANDE2.

Évaluer OPÉRANDE1 + OPÉRANDE2 et enregistrer le résultat dans RÉSULTAT.

Lire RÉSULTAT et afficher sa valeur courante à l'écran.

4 Langage de programmation

4.1 Moyen de communication

Afin de pouvoir être exécuté par un ordinateur, un algorithme doit être implémenté, autrement dit décrit en code source, en utilisant un langage de programmation. C'est le moyen de le communiquer à l'ordinateur.

À ce jour, il existe une multitude de langages de programmation chacun plus ou moins adapté aux différents types de programmation.

Contrairement aux langues vivantes humaines, dans les langages de programmation, il n'y a pas de mots, de phrases, de paragraphes, etc. Ils sont composés de chaînes de caractères, de variables, de mots clés, d'expressions arithmétiques ou logiques, d'instructions, de fonctions, etc.

Par exemple, dans Listage 1, nous proposons une implémentation, en langage de programmation C, de notre algorithme d'addition présenté dans Exemple 1.

#include <stdio.h>

int main(void) {
  int operande1 = 0, operande2 = 0, resultat = 0;

  scanf(" %d", &operande1);
  scanf(" %d", &operande2);

  resultat = operande1 + operande2;

  printf("%d\n", resultat);

  return 0;
}

Ici, int est un mot-clé qui désigne le type de valeur que les variables, déclarées et initialisées à 0, operande1, operande2 et resultat doivent prendre. En occurence, ce sont des valeurs entières, aussi bien positives que négatives. Le point-virgule marque la fin d'une instruction du programme. scanf(...) et printf(...) représentent des appels de fonctions. En occurence, des fonctions scanf et printf permettant respectivement de lire une entrée utilisateur pour sauvegarder la valeur lue dans une variable et d'afficher une chaîne de caractères à l'écran. Les éléments entre les parenthèses sont les valeurs de paramètres d'entrée des fonctions. Celles-ci seront traitées par les instructions composant les fonctions et conditionnent la sortie, ou bien le produit, de ces dernières. Le premier paramère de la fonction scanf est une chaîne de caractères qui spécifie le format de données attendu à l'entrée utilisateur. En occurence, " %d" désigne une valeur entière signée. Le second paramère est l'adresse d'une variable en mémoire où la valeur lue doit être enregistrée. En occurence, &operande1 correspond à l'adresse de la variable operande1. De même pour la lecture de la seconde opérande. Dans le cas de la fonction printf, le premier paramètre est une chaîne de caractères qui spécifie le contenu et le format de l'affichage à l'écran. "%d\n" veut dire, que nous souhaitons afficher une valeur entière signée suivie d'un retour à la ligne. Enfin, operande1 + operande2 est une expression arithmétique qui représente l'addition, via l'opérateur +, des valeurs que portent les variables operande1 et operande2. Le résultat de cette expréssion arithmétique est enregistré dans la variable resultat au moyen de l'opérateur d'affectation de valeur qui est le signe =.

4.2 Classement

4.2.1 Par niveau d'abstraction

Différents langages de programmation ont un niveau d'abstraction plus ou moins élevé. Le langage de niveau le plus bas est le langage machine, autrement dit le langage binaire, qui n'utilise que deux éléments d'expression, les chiffres zéro et un. Il ne fait aucune abstraction de la couche matérielle qui n'est qu'un assemblage de circuits électriques et portes logiques par où soit le courant circule (1) ou ne circule pas (0).

Puis, nous retrouvons le langage d'instructions symboliques, appelé assembleur, qui reste de bas niveau, très proche du matériel et spécifique à un type d'architecture d'ordinateur en particulier (amd64, i686, arm, arm64, mips, …). Le niveau d'expressivité de l'assembleur est nettement plus élevé que celui du langage binaire mais il n'en est pas moins que ses éléments d'expression restent assez limités par rapport aux langages de plus haut niveau, tels que C.

Dans Listage 2, nous illustrons la syntaxe de l'assembleur pour l'architecture mips à travers d'une implémentation de notre programme d'addition (voir Exemple 1 et Listage 1).

.data

operande1: .word 0
operande2: .word 0
resultat: .word 0

.text
.globl __main

__main:

li $v0,5
syscall
sw $v0,operande1

li $v0,5
syscall
sw $v0,operande2

lw $t0,operande1
lw $t1,operande2
add $t2,$t0,$t1
sw $t2,resultat

lw $a0,resultat
li $v0,1
syscall

li $v0,10
syscall

Plus le niveau d'abstraction d'un langage est élevé, plus il fait abstraction, vis à vis du programmeur, notamment des aspects de la couche matérielle (registres du processeur, adressage en mémoire, …) ou système (appels systèmes de lecture de fichiers, …) et plus il simplifie l'implémentation de concepts complexes.

Par exemple, pour concevoir un logiciel de pilotage d'un capteur thermique, nous nous orienterons probablement vers un langage de plus bas niveau pour garder la main sur la couche matérielle tel que C. Par contre, pour programmer un logiciel de gestion de comptabilité, nous choisirons plutôt un langage avec un haut niveau d'abstraction tel que C++, Java ou encore C#.

4.2.2 Par approche de programmation

Différents problématiques exigent différentes approches de programmation. Dans le monde de la programmation, nous allons retrouver des langages de programmation impératifs tels que C, Pascal ou Fortran; orientés objet tels que C++, Java ou C#; fonctionnels tels que Caml, Lisp ou Scheme; logiques tels que Prolog; de prototypage tel que Lisaac.

4.2.3 Par domaine d'utilisation

Différents domaines de programmation utilisent différents langages pour mieux répondre à leurs besoins spécifiques. Par exemple, en programmation Web nous allons retrouver des langages comme PHP ou JavaScript. Pour gérer une base de données, nous allons utiliser des langages de type SQL, etc.

À la fin, peu importe le niveau d'abstraction, d'approche de programmation ou de type de logiciel programmé, notre code source doit être soit traduit en langage machine, autrement dit compilé par un logiciel spécifique appelé compilateur, ou interprété par un logiciel spécifique appelé interpréteur. Dans ce cas, le code source n'est pas traduit en binaire mais ses instructions sont au fur et à mesure interprétées et directement exécutées par un interpréteur du langage en question. Par conséquence, les logiciels interprétés ont vocation à être moins performants que les logiciels compilés.

5 Programmation en langage C

Si nous avons pris le temps d'introduire la programmation et ses aspects en général avant d'exposer les spécificités du langage C en particulier, c'est parceque nous estimons qu'il est vital de comprendre ces notions pour être capable de considérer un problème donné, le synthétiser, le décrire sous forme d'un algorithme pour pouvoir implémenter ce dernier et déléguer la résolution du problème lui-même à un ordinateur de manière efficace.

Appréhender cette façon de réfléchir et résoudre des problèmes n'est pas facile et ne s'apprend pas du jour au lendemain. Ce n'est qu'en s'exerçant et en travaillant que l'on assimile cette logique.

C est un langage de programmation impératif développé par Dennis Ritchie dans les années 1970 au Bell Labs, dans l'État de New Jersey aux États-Unis.

C'est un langage de bas niveau avec une syntaxe riche mais qui peut sembler difficile à apprendre.

Dans la suite de ce chapitre, nous allons revoir les différentes notions du langage C vues en cours à travers une collection d'exercices triés par thème. Pour chaque exercice, le niveau de difficulté est également précisé et un corrigé détaillé est proposé.

5.1 Variables, entrées et sorties utilisateur

5.1.1 BASIQUE Déclaration, initialisation, accès aux variables

5.1.1.1 Énoncé

Écrivez un programme pour afficher une valeur à l'écran.

Dans un premier temps, votre programme demandera à l'utilisateur d'entrer une valeur, entière ou à virgule flottante, qui sera enregistrée dans une variable de type correspondant.

Ensuite, votre programme affichera la valeur de cette variable à l'écran.

Par exemple, pour la valeur 22, votre programme devra produire la sortie similaire à la suivante :

Entrez une valeur entière : 22
Vous avez entré la valeur : 22
5.1.1.2 Corrigé

Il nous faut d'abord inclure la bibliothèque stdio.h pour avoir accès aux fonctions scanf et printf.

#include <stdio.h>

Puis, dans notre fonction principale, nous utilisons la variable valeur et la fonction scanf pour capturer la valeur à afficher que l'utilisateur aura entrée depuis la ligne de commande.

int main(void) {;
  int valeur;

  printf("Entrez une valeur entière : ");
  scanf(" %d", &valeur);

Enfin, nous affichons la valeur capturée à l'écran à l'aide de la fonction printf et nous terminons le programme.

  printf("Vous avez entré la valeur : %d\n", valeur);

  return 0;
}

Voir l'intégrale de la correction dans le fichier variables.c prêt à compiler et exécuter.

5.2 Conditionnel

5.2.1 BASIQUE Suis-je majeur.e ?

5.2.1.1 Énoncé

Écrivez un programme pour déterminer si l'utilisateur est une personne majeure en fonction de son âge.

Dans un premier temps, votre programme demandera à l'utilisateur d'entrer son âge sous forme d'une valeur entière qui sera enregistrée dans une variable de de type entier.

Ensuite, votre programme affichera à l'écran la phrase Vous êtes majeur.e ! si l'âge de l'utilisateur est supérieur ou égal à 18 et la phrase Vous n'êtes pas majeur.e ! sinon.

5.2.1.2 Corrigé

Il nous faut d'abord inclure la bibliothèque stdio.h pour avoir accès aux fonctions scanf et printf.

#include <stdio.h>

Puis, nous demandons à l'utilisateur d'entrer son âge et capturons la valeur en utilisant scanf.

int main(void) {
  int age;

  printf("Entrez votre âge : ");
  scanf(" %d", &age);

À l'aide d'une expression conditionnelle if, nous vérifions si la valeur dans age est strictement inférieure à 18. Si c'est le cas, nous affichons le message disant que l'utilisateur n'est pas majeur. Autrement, nous affichons un message confirmant qu'il est majeur. Puis, on termine le programme.

  if(age < 18) {
    printf("Vous n'êtes pas majeur.e !\n");
  } else {
    printf("Vous êtes majeur.e !\n");
  }

  return 0;
}

Voir l'intégrale de la correction dans le fichier majeur-ou-pas.c prêt à compiler et exécuter.

5.2.2 INTERMÉDIAIRE Puis-je conduire ?

5.2.2.1 Énoncé

Écrivez un programme pour déterminer si l'utilisateur est une personne est en âge de conduire une voiture, seule ou accompagnée.

Dans un premier temps, votre programme demandera à l'utilisateur d'entrer son âge sous forme d'une valeur entière qui sera enregistrée dans une variable de de type entier.

Ensuite, votre programme affichera à l'écran la phrase Vous êtes en âge de conduire, mais uniquement accompagné.e.s ! si l'âge de l'utilisateur est supérieur ou égal à 16 et strictement inférieur à 18; la phrase Vous êtes en âge de conduire ! si l'âge de l'utilisateur est supérieur ou égal à 18; la phrase Vous n'êtes pas en âge de conduire ! dans tous les autres cas.

5.2.2.2 Corrigé

Après l'inclusion de stdio.h, nous demandons à l'utilisateur d'entrer son âge et capturons la valeur avec scanf dans la variables age.

#include <stdio.h>

int main(void) {
  int age;

  printf("Entrez votre âge : ");
  scanf(" %d", &age);

Puis, avec un conditionnel if, nous conditionnons le message à afficher qui est différent si l'utilisateur au moins 18 ans, a entre 16 et 18 ans ou a moins de 16 ans (tous les autres cas). Enfin, nous terminons le programme.

  if(age >= 18) {
    printf("Vous êtes en âge de conduire !\n");
  } else if(age >= 16 && age < 18) {
    printf("Vous êtes en âge de conduire, mais uniquement accompagné.e.s !\n");
  } else {
    printf("Vous n'êtes pas en âge de conduire !");
  }

  return 0;
}

Voir l'intégrale de la correction dans le fichier puis-je-conduire.c prêt à compiler et exécuter.

5.2.3 INTERMÉDIAIRE Noms des mois

5.2.3.1 Énoncé

Écrivez un programme pour déterminer le nom d'un mois en fonction de sa position dans le calendrier allant de 1 à 12.

Dans un premier temps, votre programme demandera à l'utilisateur d'entrer un numéro de mois sous forme d'une valeur entière qui sera enregistrée dans une variable de de type entier.

Ensuite, votre programme affichera à l'écran le nom du mois correspondant si ce mois existe, à savoir si l'utilisateur a entré une valeur comprises entre 1 et 12 inclus. Dans le cas contraire, votre programme affichera un message d'erreur.

Pour vous simplifier la tâche, vous pouvez utiliser la structure de conditionnel multiple switch.

Par exemple, en entrant 8, votre programme devra produire la sortie similaire à la suivante :

Entrez un numéro de mois : 8
Le mois correspodant s'appelle : août

Une correction est proposée dans le listage ci-dessous.

5.2.3.2 Corrigé

Tout d'abord, il nous faut demander à l'utilisateur d'entrer un numéro de mois et captuer la valeur dans une variable de type entier, ici appelée mois.

#include <stdio.h>

int main(void) {
  int mois;

  printf("Entrez un numéro de mois : ");
  scanf(" %d", &mois);

Puis, en nous servant du conditionnel multiple switch, nous affichons le nom du mois correspodant à la valeur dans mois. Si la valeur n'est pas entre 1 et 12 compris, nous affichons un message d'erreur.

  printf("Le mois correspodant s'appelle : ");

  switch(mois) {
    case 1:
      printf("janvier\n");
      break;
    case 2:
      printf("février\n");
      break;
    case 3:
      printf("mars\n");
      break;
    case 4:
      printf("avril\n");
      break;
    case 5:
      printf("mai\n");
      break;
    case 6:
      printf("juin\n");
      break;
    case 7:
      printf("juillet\n");
      break;
    case 8:
      printf("août\n");
      break;
    case 9:
      printf("septembre\n");
      break;
    case 10:
      printf("octobre\n");
      break;
    case 11:
      printf("novembre\n");
      break;
    case 12:
      printf("decembre\n");
      break;
    default:
      printf("?\n");
      printf("Il n'existe pas de mois portant le numéro %d!", mois);
  }

  return 0;
}

Voir l'intégrale de la correction dans le fichier mois.c prêt à compiler et exécuter.

5.2.4 INTERMÉDIAIRE Calculatrice rudimentaire

5.2.4.1 Énoncé

Écrivez un programme pour effectuer différentes opérations arithmétiques avec deux nombres donnés comme avec une calculatrice rudimentaire.

Dans un premier temps, votre programme demandera à l'utilisateur d'entrer deux nombres (opérandes) sous forme de valeurs à virgule flottante qui seront enregistrées dans des variables de de type flottant.

Puis votre programme demandera à l'utilisateur d'entrer un numéro identifiant l'opération arithmétique à effectuer avec les deux opérandes. L'utilisateur aura le choix entre l'addition (1), la soustraction (2), la multiplication (3) et la division (4).

Ensuite, votre programme affichera à l'écran le résultat de l'opération effectuée. Si un identifiant d'opération invalide est entré, votre programme devra afficher un message d'erreur.

Comme dans l'exercice précédent, vous pouvez vous servir de la structure de contrôle switch lors de l'écriture de votre programme.

Par exemple, en entrant les opérandes 12.7 et 10.3, puis le numéro d'opération 1, votre programme devra produire une sortie similaire à la suivante :

Entrez la 1ère opérande : 12.7
Entrez la 2e opérande : 10.3

Voici la liste des opérations possibles :
- addition (1)
- soustraction (2)
- multiplication (3)
- division (4)

Entrez le numéro de l'opération à effectuer : 1

Résultat : 23.000000

Comme dans l'exercice précédent, vous pouvez vous servir de la structure de contrôle switch lors de l'écriture de votre programme.

5.2.4.2 Corrigé

Dans un premier temps, nous devons demander à l'utilisateur deux opérandes de type flottant et capturer leurs valeurs avec scanf. Notons que %f dans l'appel à celle-ci indique que l'on attend une valeur flottante à l'entrée.

#include <stdio.h>

int main(void) {
  float operande1, operande2, resultat;
  int operation;

  printf("Entrez la 1ère opérande : ");
  scanf(" %f", &operande1);

  printf("Entrez la 2e opérande : ");
  scanf(" %f", &operande2);

Ensuite, nous demandons à l'utilisateur d'entrer l'identificateur de l'opération à effectuer tout en lui affichant toutes les possibilités au préalable.

  printf("Voici la liste des opérations possibles :\n");
  printf("- addition (1)\n");
  printf("- soustraction (2)\n");
  printf("- multiplication (3)\n");
  printf("- division (4)\n");

  printf("Entrez le numéro de l'opération à effectuer : ");
  scanf(" %d", &operation);

Enfin, en fonction de l'identificateur lu, nous effectuons l'opération désirée et enregistrons le résultat dans la variable resultat dont la valeur nous affichons avant de terminer le programme. Le conditionnel multiple switch nous sert ici pour conditionner l'opération à effectuer en fonction de la valeur lue dans operation.

  switch(operation) {
    case 1:
      resultat = operande1 + operande2;
      break;
    case 2:
      resultat = operande1 - operande2;
      break;
    case 3:
      resultat = operande1 * operande2;
      break;
    case 4:
      resultat = operande1 / operande2;
      break;
    default:
      printf("Opération inconnue !\n");
      return 1;
  }

  printf("Résultat: %f\n", resultat);

  return 0;
}

Voir l'intégrale de la correction dans le fichier calculatrice.c prêt à compiler et exécuter.

5.3 Boucles

5.3.1 BASIQUE Compteur

5.3.1.1 Énoncé

Écrivez un programme pour afficher tous les nombres allant de 0 jusqu'à une borne n donnée.

Dans un premier temps, votre programme demandera à l'utilisateur d'entrer une borne sous forme d'une valeur entière qui sera enregistrée dans une variable de type entier.

Ensuite, votre programme affichera à l'écran tous les nombres allant de 0 jusqu'à la valeur contenue dans cette variable à raison d'une valeur par ligne.

Par exemple, pour n égal à 5, votre programme devra produire la sortie similaire à la suivante :

0
1
2
3
4
5
5.3.1.2 Corrigé

Au début, nous demandons à l'utilisateur d'entrer une borne entière et capturons la valeur dans la variable borne.

#include <stdio.h>

int main(void) {
  int i, borne;

  printf("Entrez une borne n : ");
  scanf(" %d", &borne);

À l'aide d'une boucle for, nous répétons l'instruction d'affichage de la valeur de la variable i pour chaque valeur entre 0 compris et la valeur dans borne exclue.

  for(i = 0; i < borne; i++) {
    printf("%d\n", i);
  }

  return 0;
}

Voir l'intégrale de la correction dans le fichier compteur.c prêt à compiler et exécuter.

5.3.2 BASIQUE Rectangle étoilé

5.3.2.1 Énoncé

Écrivez un programme pour dessiner à l'écran un rectangle étoilé d'une largeur et d'une hauteur données.

Dans un premier temps, votre programme demandera à l'utilisateur d'entrer la largeur et la hauteur du rectangle sous forme de deux valeurs entières qui seront enregistrées dans deux variables de type entier.

Ensuite, votre programme affichera à l'écran le rectangle respectant ces dimensions en utilisant le caractère *.

Par exemple, pour la largeur de 5 et la hauteur de 3, votre programme devra produire le dessin suivant :

 * * * * *
 * * * * *
 * * * * *
5.3.2.2 Corrigé

Nous commençons par recupérer la largeur et la hauteur, deux valeurs entières, du rectangle que notre programme dessinera.

#include <stdio.h>

int main(void) {
  int i, j, largeur, hauteur;

  printf("Entrez la largeur : ");
  scanf(" %d", &largeur);

  printf("Entrez la hauteur : ");
  scanf(" %d", &hauteur);

En utilisant deux boucles for imbriquées l'une dans l'autre, nous parcourons hauteur lignes et dans chacune d'elles, nous affichons largeur étoiles. Pour obtenir une forme de rectangle, nous ajoutons un saut à la ligne au bout de chaque ligne.

  for(i = 0; i < hauteur; i++) {
    for(j = 0; j < largeur; j++) {
      printf(" * ");
    }

    printf("\n");
  }

  return 0;
}

Voir l'intégrale de la correction dans le fichier rectangle-etoile.c prêt à compiler et exécuter.

5.3.3 INTERMÉDIAIRE Multiplication par addition

5.3.3.1 Énoncé

Écrivez un programme pour effectuer l'addition de deux nombres quelconques sans utiliser l'opérateur de multiplication *.

Dans un premier temps, votre programme demandera à l'utilisateur d'entrer deux opérandes sous forme de deux valeurs entières qui seront enregistrées dans deux variables de type entier.

Ensuite, votre programme se servira d'une boucle pour calculer le résultat de la multiplication de ces opérandes et l'afficher à l'écran avant de terminer son exécution.

Par exemple, avec les opérandes 3 et 25, votre programme devra effectuer le calcul 25 + 25 + 25 et produire une sortie similaire à la suivante :

Entrez la 1ère opérande : 3
Entrez la 2e opérande : 25

Résultat de la multiplication (par addition) : 75
5.3.3.2 Corrigé

Pour commencer, nous recupérons deux opérandes entières pour pouvoir effectuer la multiplication de operande2 par operande1.

#include <stdio.h>

int main(void) {
  int i, operande1, operande2, resultat = 0;

  printf("Entrez la 1ère opérande : ");
  scanf(" %d", &operande1);

  printf("Entrez la 2e opérande : ");
  scanf(" %d", &operande2);

Au lieu d'utiliser simplement l'opérateur de multiplication *, nous nous servons d'une boucle for pour augmenter operande1 fois la valeur de la variable resultat de la valeur dans operande2. Autrement dit, resultat contiendra à la sortie de la boucle, operande1 fois operande2 ce qui revient à multiplier les deux opérandes entre elles.

  for(i = 0; i < operande1; i++) {
    resultat = resultat + operande2;
  }

  printf("Résultat de la multiplication (par addition): %d\n", resultat);

  return 0;
}

Voir l'intégrale de la correction dans le fichier multiplication-par-addition.c prêt à compiler et exécuter.

5.3.4 INTERMÉDIAIRE D'autres dessins étoilés

5.3.4.1 Énoncé

Écrivez un ou plusieurs programmes pour dessiner à l'écran des formes étoilées d'une taille donnée.

Dans un premier temps, votre programme demandera à l'utilisateur d'entrer la taille de l'objet en nombres de lignes sous forme de d'une valeur entière qui sera enregistrée dans une variable de type entier.

Ensuite, votre programme affichera à l'écran le dessin de la taille correspondante en utilisant le caractère * ou le caractère O. Par exemple, pour une taille de 5, votre programme devra produire les dessins suivants :

  1.   *
      * *
      * * *
      * * * *
      * * * * *
    
  2.   * * * * *
        * * * *
          * * *
            * *
              *
    
  3.           *
            * *
          * * *
        * * * *
      * * * * *
    
  4.   * * * * *
      * * * *
      * * *
      * *
      *
    
  5.   O * * * *
      * O * * *
      * * O * *
      * * * O *
      * * * * O
    
5.3.4.2 Corrigé

Nous démarrons par demander la taille pour les dessins à afficher. Puisque la hauteur et la largeur de nos dessins doit être la même, nous recupérons une seule valeur dans la variable taille.

#include <stdio.h>

int main(void) {
  int i, j, taille;

  printf("Entrez la taille : ");
  scanf(" %d", &taille);

Pour dessiner le premier dessin, nous affichons sur taille lignes i + 1 étoile. Comme i évolue, sur la ligne 1, nous afficherons 1 étoile. Puis, sur la ligne 2, 2 étoiles et ainsi de suite jusqu'à aboutir à un triangle de taille lignes. Il ne faut pas oublier de séparer les lignes par un saut à la ligne !

Le saut à la ligne suivant sert à séparer le premier dessin du suivant.

  for(i = 0; i < taille; i++) {
    for(j = 0; j < i + 1; j++) {
      printf(" * ");
    }

    printf("\n");
  }

  printf("\n");

Le second dessin est l'inverse du premier. Ici, nous affichons sur taille lignes d'abord i espacements puis à partir de la diagonale jusqu'à la taille=^{ème} colonne des étoiles. Ainsi, sur la ligne 1, nous affichons 0 espacements et =taille étoiles. Sur la ligne 2, 1 espacement et taille - 1 étoiles et ainsi de suite.

  for(i = 0; i < taille; i++) {
    for(j = 0; j < i; j++) {
      printf("   ");
    }

    for(j = i; j < taille; j++) {
      printf(" * ");
    }

    printf("\n");
  }

  printf("\n");

Pour effectuer le troisième dessin, nous affichons sur taille lignes des espacements depuis le début de chaque ligne jusqu'à la colonne précédant la diagonale puis nous remplissons le reste de la ligne par des étoiles. Ainsi, sur la ligne 1, nous affichons d'abord taille - 1 espacements suivis d'une seule étoile. Sur la ligne 2, taille - 2 espacements suivis de deux étoiles et ainsi de suite.

  for(i = 0; i < taille; i++) {
    for(j = 0; j < taille - i - 1; j++) {
      printf("   ");
    }

    for(j = taille - i - 1; j < taille; j++) {
      printf(" * ");
    }

    printf("\n");
  }

  printf("\n");

Dans le quatrième dessin, chaque ligne des taille lignes commence avec des étoiles. Puis, à partir de la colonne suivant la diagonale, des espacements sont affichés. Ainsi, sur la ligne 1, nous affichons taille étoiles et aucun espacement. Sur la ligne 2, taille - 1 étoiles et 1 espacement et ainsi de suite.

  for(i = 0; i < taille; i++) {
    for(j = 0; j < taille - i; j++) {
      printf(" * ");
    }

    printf("\n");
  }

  printf("\n");

Le dernier dessins est un rectangle formé d'étoiles à l'exception de la diagonale. Alors, lorsque l'on se trouve sur la diagonale, autrement dit lorsque i égale j, nous affichons O au lieu d'une étoile.

  for(i = 0; i < taille; i++) {
    for(j = 0; j < taille; j++) {
      if(i == j) {
        printf(" O ");
      } else {
        printf(" * ");
      }
    }

    printf("\n");
  }

  return 0;
}

Voir l'intégrale de la correction dans le fichier dessins-etoiles.c prêt à compiler et exécuter.

5.3.5 AVANCÉ Maître.sse de dessin

5.3.5.1 Énoncé

Reprenez le programme de l'exercice précédent et modifier le de façon à ce qu'il dessine les formes suivantes :

  1.        *
          * *
         * * *
        * * * *
       * * * * *
    
  2.   1
      2 2
      3 3 3
      4 4 4 4
      5 5 5 5 5
    
  3.   1
      2 3
      4 5 6
      7 8 9 10
      11 12 13 14 15
    
5.3.5.2 Corrigé

Comme dans l'exercice précédent, nous recupérons d'abord la taille des objets à dessiner dans taille.

#include <stdio.h>

int main(void) {
  int i, j, taille;

  printf("Entrez la taille : ");
  scanf(" %d", &taille);

Pour le premier dessin, nous dessinons taille lignes où dans chaque ligne il y a taille - i - 1 espaces suivis de i étoiles.

  for(i = 0; i < taille; i++) {
    for(j = 0; j < taille - i -1; j++) {
      printf(" ");
    }

    for(j = 0; j < i + 1; j++) {
      printf("* ");
    }

    printf("\n");
  }

  printf("\n");

Dans le second dessin, nous affichons taille lignes et dans chacune d'elle i exemplaires de la valeur de i + 1 (pour commencer avec le 1 au lieu de 0). Ainsi, sur la ligne 1, nous affichons une fois 1. Sur la ligne 2, deux fois 2 et ainsi de suite.

  for(i = 0; i < taille; i++) {
    for(j = 0; j < i + 1; j++) {
      printf(" %d ", i + 1);
    }

    printf("\n");
  }

  printf("\n");

Dans le troisième dessin, similaire au précédant, nous nous servons d'une autre variable c. Sur chacune des taille lignes que nous affichons, figurent i exemplaires de la valeur de c qui augmente après chaque affichage de sa valeur. Au début c vaut 1. Ainsi, sur la ligne 1, nous affichons une fois 1. Sur la ligne 2, un 2 et un 3 et ainsi de suite.

  int c = 1;
  for(i = 0; i < taille; i++) {
    for(j = 0; j < i + 1; j++) {
      printf(" %d ", c++);
    }

    printf("\n");
  }

  return 0;
}

Voir l'intégrale de la correction dans le fichier maitre-sse-de-dessin.c prêt à compiler et exécuter.

5.4 Tableaux à taille fixe

5.4.1 BASIQUE Déclaration, initialisation, accès aux valeurs des tableaux

5.4.1.1 Énoncé

Écrivez un programme pour remplir un tableau de valeurs et afficher son contenu à l'écran.

Dans un premier temps, votre programme demandera à l'utilisateur d'entrer, une par une, 5 valeurs (entières ou à virgule flottante) qui seront enregistrées dans un tableau de la même taille et de type correspondant.

Ensuite, votre programme parcourera ce tableau et affichera les valeurs du tableau à l'écran à raison d'une valeur par ligne avant de terminer son exécution.

i 0 1 2 3 4
tableau[i] 12 4 5 100 11

Par exemple, pour le tableau de valeur ci-dessus, votre programme devrait afficher les lignes suivantes à la sortie :

Entrez la 1e valeur : 12
Entrez la 2e valeur : 4
Entrez la 3e valeur : 5
Entrez la 4e valeur : 100
Entrez la 5e valeur : 11

12
4
5
100
11
5.4.1.2 Corrigé

Dans notre implémentation, après avoir déclaré un tableau de 5 entiers, nous utilisons une boucle for pour recupérer chacune des 5 valeurs du tableau de l'utilisateur.

#include <stdio.h>

int main(void) {
  int i;
  int tableau[5];

  for(i = 0; i < 5; i++) {

Par exemple, pour i égal à 1, l'instruction suivante affiche Entrez la 2e =valeur : =.

    printf("Entrez la %de valeur : ", i + 1);
    scanf(" %d", &tableau[i]);
  }

Enfin, nous refaisons une boucle à 5 itérations pour afficher, une par une, les valeurs du tableau tableau.

  for(i = 0; i < 5; i++) {
    printf("%d\n", tableau[i]);
  }

  return 0;
}

Voir l'intégrale de la correction dans le fichier tableaux.c prêt à compiler et exécuter.

5.4.2 INTERMÉDIAIRE Moyenne

5.4.2.1 Énoncé

Pour rappel, la moyenne d'un ensemble de valeurs est définie comme la somme de celles-ci divisée par leur nombre. Par exemple, la moyenne des 3 valeurs suivantes 12,0 puis 5,5 et 10,0 se calcule de façon suivante :

\begin{gather*} \frac{(12,0 + 5,5 + 10,0)}{3} = 9,17 \end{gather*}

Écrivez un programme pour calculer la moyenne d'un ensemble de valeurs donné.

Dans un premier temps, votre programme demandera à l'utilisateur d'entrer, une par une, 5 valeurs à virgule flottante qui seront enregistrées dans un tableau de la même taille et de type correspondant.

Ensuite, votre programme parcourera ce tableau afin de calculer la moyenne de ses valeurs et l'afficher à l'écran avant de terminer son exécution.

Par exemple, pour le tableau de valeur ci-dessous, la réponse de votre programme devrait être : La moyenne vaut 5,18.

Ici, la première ligne contient les indices des cases du tableau et la seconde ligne les valeurs des cases correspondantes.

i 0 1 2 3 4
tableau[i] 12.0 4.3 5.7 1.9 2.0
5.4.2.2 Corrigé

Tout d'abord, nous recupérons de l'utilisateur 5 valeurs flottantes pour remplir le tableau tableau à l'aide d'une boucle for à 5 itérations.

#include <stdio.h>

int main(void) {
  int i;
  float moyenne = 0.0;
  float tableau[5];

  for(i = 0; i < 5; i++) {

Par exemple, pour i égal à 1, l'instruction suivante affiche Entrez la 2e valeur :.

    printf("Entrez la %de valeur : ", i + 1);
    scanf(" %f", &tableau[i]);
  }

En rebouclant sur les éléments du tableau, nous calculons leur somme et enregistrons le résultat dans la variable moyenne.

  for(i = 0; i < 5; i++) {
    moyenne = moyenne + tableau[i];
  }

Puis, pour obtenir la moyenne, nous devons diviser la somme par le nombre de valeurs (5) et afficher le résultat.

  moyenne = moyenne / 5.0;

%.2f dans l'appel à scanf permet de restreindre l'affichage d'une valeur flottante à deux chiffres après la virgule.

  printf("La moyenne vaut %.2f\n", moyenne);

  return 0;
}

Voir l'intégrale de la correction dans le fichier moyenne.c prêt à compiler et exécuter.

5.4.3 INTERMÉDIAIRE Minimum

5.4.3.1 Énoncé

Écrivez un programme pour retrouver la valeur minimale d'un ensemble de valeurs donné.

Dans un premier temps, votre programme demandera à l'utilisateur d'entrer, une par une, 5 valeurs entières qui seront enregistrées dans un tableau d'entiers de la même taille.

Ensuite, votre programme parcourera ce tableau à la recherche de la valeur minimale qu'il affichera à l'écran avant de terminer son exécution.

Par exemple, pour le tableau de valeurs ci-dessous, la réponse de votre programme devrait être : La valeur minimale est 4.

Ici, la première ligne contient les indices des cases du tableau et la seconde ligne les valeurs des cases correspondantes.

i 0 1 2 3 4
tableau[i] 12 4 5 100 11
5.4.3.2 Corrigé

Pour commencer, nous recupérons 5 valeurs entières dans le tableau tableau.

#include <stdio.h>

int main(void) {
  int i, minimum;
  int tableau[5];

  for(i = 0; i < 5; i++) {

Par exemple, pour i égal à 1, l'instruction suivante affiche Entrez la 2e =valeur : =.

    printf("Entrez la %de valeur : ", i + 1);
    scanf(" %d", &tableau[i]);
  }

Au début, le programme supposera que le minimum est la première valeur du tableau puisqu'il n'a pas la connaissance globale de toutes les valeurs de celui-ci.

  minimum = tableau[0];

Puis, il parcourera les cases suivantes du tableau pour vérifier si une valeur plus petite que le minimum présumé au début ne se trouve dans le tableau. Si c'est le cas, cette valeur deviendra le nouveau minimum. Ceci garantira, qu'une que le programme aura vu toutes les cases du tableau, la variable nommée minimum contiendra bien la plus petite valeur du tableau. Celle-ci sera affiché juste avant la terminaison du programme.

  for(i = 1; i < 5; i++) {
    if(tableau[i] < minimum) {
      minimum = tableau[i];
    }
  }

  printf("La valeur minimale est %d\n", minimum);

  return 0;
}

Voir l'intégrale de la correction dans le fichier minimum.c prêt à compiler et exécuter.

5.4.4 INTERMÉDIAIRE Maximum

5.4.4.1 Énoncé

Écrivez un programme pour retrouver la valeur maximale d'un ensemble de valeurs donné. Les consignes sont analogues à l'exercice précédent.

Par exemple, pour le tableau de valeur ci-dessous, la réponse de votre programme devrait être : La valeur maximale est 17.

Ici, la première ligne contient les indices des cases du tableau et la seconde ligne les valeurs des cases correspondantes.

0 1 2 3 4
3 -4 15 17 3
5.4.4.2 Corrigé

Dans ce cas, nous utilisons le même algorithme que dans le cas du minimum sauf que nous inverons le test dans la boucle finale.

#include <stdio.h>

int main(void) {
  int i, maximum;
  int tableau[5];

  for(i = 0; i < 5; i++) {
    printf("Entrez la %de valeur : ", i + 1);
    scanf(" %d", &tableau[i]);
  }

  maximum = tableau[0];

  for(i = 1; i < 5; i++) {
    if(tableau[i] > maximum) {
      maximum = tableau[i];
    }
  }

  printf("La valeur maximale est %d\n", maximum);

  return 0;
}

Voir l'intégrale de la correction dans le fichier maximum.c prêt à compiler et exécuter.

5.4.5 INTERMÉDIAIRE Palindrome

Un nombre est un palindrome si sa valeur ne change pas que l'on lise ses chiffres de gauche à droite ou de droite à gauche. Par exemple, les nombres 1 234 321, 3 553, 77 877 ou encore 111 sont des palindromes. Au contraire, les nombres 123 456, 453 646 ou encore 14 ne sont pas des palindromes car 123 456 ≠ 654 321, 453 646 ≠ 646 453 et 14 ≠ 41.

5.4.5.1 Énoncé

Écrivez un programme pour vérifier si un nombre donné est un palindrome. Dans ce cas-ci, nous allons uniquement considérer des valeurs entières à exactement 5 chiffres (e. g. 34 534 mais pas 414 ni 1 234 321) pour nous simplifier la tâche.

Dans un premier temps, votre programme demandera à l'utilisateur d'entrer, une par une, les 5 chiffres d'un nombre entier quelconque et les enregistrera dans un tableau d'entiers de la même taille. Par exemple, dans le cas du nombre 34 543 le tableau d'entiers contiendra les valeurs comme indiqué ci-dessous.

Ici, la première ligne contient les indices des cases du tableau et la seconde ligne les valeurs des cases correspondantes.

i 0 1 2 3 4
tableau[i] 3 4 5 4 3

La sortie de votre programme devra être similaire à celle ci-dessous.

Entrez les chiffres d'un nombre à tester un par un !
Entrez le chiffre No. 1 : 3
Entrez le chiffre No. 2 : 4
Entrez le chiffre No. 3 : 5
Entrez le chiffre No. 4 : 4
Entrez le chiffre No. 5 : 3
Le nombre 34543 est un palindrome.
5.4.5.2 Corrigé

Avant tout, nous déclarons un tableau d'entiers de taille 5 et nous demandons à l'utilisateur d'entrer le nombre à vérifier chiffre par chiffre que nous sauvegardons dans ce tableau à l'aide d'une boucle.

#include <stdio.h>

int main(void) {
  int chiffres[5];

  printf("Entrez les chiffres d'un nombre à tester un par un !\n");

  int i;
  for(i = 0; i < 5; i++) {
    /* Par exemple, pour i égal à 1, l'instruction suivante affiche :
       "Entrez le chiffre No. 2 : " */
    printf("Entrez le chiffre No. %d : ", i + 1);
    scanf(" %d", &tableau[i]);
  }

Ensuite, nous parcourons la moitié du tableau, soit 5 ÷ 2 = 2 (en division entière), afin de vérifier que le premier chiffre est égal au dernier, le second à l'avant-dernier et ainsi de suite.

Si un des couples de chiffres vérifiés n'est pas constitué par deux mêmes chiffres, nous affichons un message d'erreur et nous terminons directement sans continuer la vérification inutilement.

  for(i = 0; i < 2; i++) {
    if(tableau[i] != tableau[4 - i]) {
      printf("Ce nombre n'est pas un palindrome !\n");
      return 1;
    }
  }

Dans le cas contraire, nous parcourons le tableau entier et affichons une réponse positive à l'écran avant de terminer l'exécution.

  printf("Ce nombre est un palindrome.\n");
  return 0;
}

Voir l'intégrale de la correction dans le fichier palindrome.c prêt à compiler et exécuter.

5.5 Chaînes de caractères

5.5.1 BASIQUE Remplacement de caractères

5.5.1.1 Énoncé

Écrivez un programme qui demande à l'utilisateur d'entrer une chaîne de caractères (mot, phrase, etc.) et qui remplace toutes les occurences du caractère a ou A par le caractère b respectivement B dans cette dernière.

Notez que les caractères accentués ne sont pas à prendre en compte !

Votre programme devra produire la sortie similaire à celle dans l'exemple ci-dessous.

Entrez une chaîne de caractères (sans accents) : Salut a toutes et a tous !
Résultat du remplacement : Sblut b toutes et b tous!
5.5.1.2 Corrigé

Dans un premier temps, nous définissons un tableau de caractères qui va contenir la chaîne entrée par l'utilisateur. Nous limitons la capacité du tableau à 256 caractères. Il pourra donc contenir des chaînes comptant au plus 255 caractères plus le caractère de terminaison \0.

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

int main(void) {
  char chaine[256];

Puis, nous demandons à l'utilisateur d'entrer une chaîne de caractères avec la fonction printf. En utilisant la fonction fgets, nous allons analyser au plus 256 caractères de la chaîne fournie sur l'entrée standard du programme stdin par l'utilisateur (en comptant le caractère de terminaison) et les sauvegarder dans le tableau chaine.

  printf("Entrez une chaîne de caractères :");
  fgets(chaine, 256, stdin);

La fonction strlen de la bibliothèque string.h, incluse dans l'en-tête du programme, nous permet de déterminer la longueur exacte de la chaîne lue à l'entrée. En effet, pour le moment nous savons uniquement que la chaîne comporte au plus 256 caractères mais pour la suite, nous avons besoin de sa longueur exacte. Pour l'exemple donné dans l'énoncé, cette fonction renvoit 26. Elle ne compte pas le caractère de terminaison !

Aussi, si l'utilisateur entre une chaîne plus longue que 256 caractères, la chaîne sauvegardée dans chaine ne sera pas proprement terminé par \0 car il n'y aura plus de place pour celui-ci. Nous devons donc nous assurer que dans tous les cas de figure, la chaîne soit bien terminée et plaçons donc le caractère de terminaison dans la dernière case du tableau chaine.

  chaine[255] = '\0';
  int longueur = strlen(chaine);

À l'aide d'une boucle, nous parcourons l'ensemble des caractères de la chaîne dans chaine à la recherche du caractère a ou A en nous les remplaçons par b respectivement B.

  int i;
  for(i = 0; i < longueur; i++) {
    if(chaine[i] == 'a') {
      chaine[i] = 'b';
    } else if(chaine[i] == 'A') {
      chaine[i] = 'B';
    }
  }

Enfin, nous affichons le résultat et terminons le programme.

  printf("Résultat du remplacement : %s\n", chaine);
  return 0;
}

Voir l'intégrale de la correction dans le fichier remplacement-de-caracteres.c prêt à compiler et exécuter.

5.5.2 INTERMÉDIAIRE Inversement de chaîne

5.5.2.1 Énoncé

Écrivez un programme qui demande à l'utilisateur d'entrer une chaîne de caractères (mot, phrase, etc.) et qui inverse l'ordre de caractères dans celle-ci et affiche le résultat à l'écran.

Votre programme devra produire la sortie similaire à celle dans l'exemple ci-dessous.

Entrez une chaîne de caractères : Comment allez-vous ?
Chaîne inversée : ? suov-zella tnemmoC
5.5.2.2 Corrigé

Dans un premier temps, nous définissons un tableau de caractères qui va contenir la chaîne entrée par l'utilisateur. Nous limitons la capacité du tableau à 256 caractères. Il pourra donc contenir des chaînes comptant au plus 255 caractères plus le caractère de terminaison \0.

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

int main(void) {
  char chaine[256];

Puis, nous demandons à l'utilisateur d'entrer une chaîne de caractères avec la fonction printf. En utilisant la fonction fgets, nous allons analyser au plus 256 caractères de la chaîne fournie sur l'entrée standard du programme stdin par l'utilisateur (en comptant le caractère de terminaison) et les sauvegarder dans le tableau chaine.

  printf("Entrez une chaîne de caractères :");
  fgets(chaine, 256, stdin);

La fonction strlen de la bibliothèque string.h, incluse dans l'en-tête du programme, nous permet de déterminer la longueur exacte de la chaîne lue à l'entrée (voir plus dans Corrigé 5.5.1.2).

Par exemple, pour la chaîne entrée dans l'énoncé, cette fonction renvoit 20.

Aussi, nous devons nous assurer qu'en cas de dépassement des 255 caractères, la chaîne soit bien terminée et plaçons donc le caractère de terminaison dans la dernière case du tableau chaine (voir plus dans Corrigé 5.5.1.2).

  chaine[255] = '\0';
  int longueur = strlen(chaine);

À l'aide d'une boucle, nous parcourons la moitié de la chaîne de caractères dans chaine en échangeant le premier caractère avec le dernier, le second avec l'avant-dernier et ainsi de suite jusqu'à ce que nous arrivions au milieu de la chaîne. De cette façon, à la sortie de la boucle, nous obtenons la chaîne de départ avec l'ordre de caractère inverse.

  int i;
  for(i = 0; i < longueur / 2; i++) {
    chaine[i] = chaine[longueur - i - 1];
  }

Enfin, nous affichons le résultat et terminons le programme.

  printf("Chaîne inversée : %s\n", chaine);
  return 0;
}

Voir l'intégrale de la correction dans le fichier inversement-de-chaine.c prêt à compiler et exécuter.

5.5.3 AVANCÉ Chiffrement de César

Appelé aussi chiffrement par décalage, le chiffrement de César est une méthode de chiffrement très simple. Pour chiffrer un texte, nous remplaçons chacune de ses lettres par une lettre à une distance fixe donnée, appellée la clé. La distance est toujours comptée dans l'ordre de l'alphabet utilisé et lorsque nous arrivons à la fin de l'alphabet, nous reprenons depuis le début.

Par exemple, considérons l'alphabet latin de base à 26 lettres de A à Z et le texte clair à chiffrer suivant :

NOUS Y SOMMES PARVENUS !

Nous prenons comme clé de chiffrement la distance 4. Ainsi, nous chiffrons notre texte en décalant chacune de ses lettres de 4 à droite bien dans le sens de l'alphabet : N + 4 = R, O + 4 = S, et ainsi de suite ce qui nous donne le résultat ci-dessous :

RSYW C WSQQIW TEVZIRYW !

Le déchiffrement d'un texte se fait en effectuant l'opération inverse. C'est-à-dire décaler toutes les lettres du texte chiffré à gauche en considérant la même distance que celle utilisée pour chiffrer.

5.5.3.1 Énoncé

Dans le cadre de cet exercice, vous allez développer un programme en langage C permettant de chiffrer et de déchiffrer un texte donné en utilisant la méthode de César décrite ci-dessus.

Au lancement, votre programme doit demander à l'utilisateur d'entrer un texte, en clair ou chiffré, la clé de chiffrement ou de déchiffrement ainsi que l'action à effectuer, à savoir le chiffrement ou le déchiffrement.

Comme l'alphabet vous allez considérer les 95 caractères afficheables de la table ASCII, entre l'espace (valeur 32) et ~ (valeur 126) ce qui vous permettra de chiffrer non seulement les lettres mais aussi d'autres caractères tels que les espaces ou les ponctuations et par la même rendre le chiffrement un peu plus robuste.

5.5.3.2 Corrigé

Au début, nous incluons les bibliothèques du langage C nécessaires pour le développement de notre programme.

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

Ensuite, nous définissons la macro LONGUEUR_MAX qui contient la longueur maximale du texte à chiffrer ou à déchiffrer que l'utilisateur pourra rentrer. Ainsi, partout dans le fichier source de notre programme, l'expression LONGUEUR_MAX sera remplacée par la valeur numérique associée.

Pour commencer nous allons considérer des chaînes de caractères de capacité maximale 1 024 caractères.

#define LONGUEUR_MAX 1024

Nous définission aussi une fonction pour le chiffrement et une pour le déchiffrement.

La fonction de chiffrement chiffrer parcours caractère par caractère le texte clair qui lui est passé via le paramètre texte_clair, décale chaque caractère de la distance passée dans cle et enregistre les caractères décalés dans la chaîne de destination texte_chiffre. Le paramètre longueur contiendra le nombre de caractère de la chaîne de caractères à traiter.

void chiffrer(
  const char texte_clair[],
  char texte_chiffre[],
  size_t longueur,
  char cle
) {
  size_t i;

  for(i = 0; i < longueur; i++) {
    texte_chiffre[i] = (texte_clair[i] - 32 + cle) % 94;
  }

  return;
}

Avant de décaler les caractères initiaux du nombre de caractères dans cle, nous devons leur soustraire 32 puisque nous ne considérons pas les 32 premiers caractères de la table ASCII dans le cadre de notre alphabet.

En utilisant l'opérateur modulo %, nous nous assurons que lorsque au décalage nous dépassons le dernier caractère de l'alphabet considéré, nous recommençons depuis le début de l'alphabet.

L'opérateur modulo % calcule le reste de la division entière de deux nombres. Par exemple, 5 ÷ 2 = 2 en division entière. Le reste est 1, car en faisant l'opération inverse 2 × 2 nous obtenons 4 et il nous manque 1 pour retrouver la valeur de départ 5. Pour obtenir ce 1, nous pouvons utiliser le modulo. Ainsi, 5 modulo 2 donne 1.

La propriété du modulo qui est intéressante pour notre programme est le fait que le résultat du modulo est forcément plus petit et du même signe que le diviseur, 2 dans le cas de l'exemple précédant, soit 1 < 2. Dans le cadre de notre programme, nous ne devons pas dépasser 94 qui est le nombre total de caractères moins 1, car nous comptons à partir de 0 en C, de notre alphabet basé sur la table ASCII (voir Section 5.5.3.1)

Prenons un exemple directement en relation avec notre problématique. Nous voulons chiffrer le caractère z ayant le code 122 dans la table ASCII avec la clé 10 :

texte_chiffre[i] = (texte_clair[i] - 32 + cle) % 94;
texte_chiffre[i] = (122 - 32 + 10) % 94;
texte_chiffre[i] = 100 % 94;
texte_chiffre[i] = 6;

Tout d'abord, nous calculons 122 - 32 qui donne 90. Ensuite, nous décalons de 10 pour obtenir 100. Cette valeur dépasse 94. Enfin, 100 modulo 94 vaut 6. Le caractère z sera donc chiffré avec la valeur 6 qui est bien comprise entre 0 et 94 inclus. Pour retrouver le code du caractère chiffré dans la table ASCII d'origine, il suffit de calculer 6 + 32 ce qui nous donne 38 correspondant au caractère &.

Notre fonction de déchiffrement dechiffrer est similaire à la fonction du chiffrement. Pour déchiffrer, nous devons effectuer le décalage dans le sens inverse.

void dechiffrer(
  const char texte_chiffre[],
  char texte_clair[],
  size_t longueur,
  char cle
) {
  size_t i;

  for(i = 0; i < longueur; i++) {
    texte_clair[i] = (texte_chiffre[i] - 32 - (cle % 94) + 94) % 94;
  }

  return;
}

Tout comme dans le cas du chiffrement, avant de décaler les caractères chiffrés dans le sens inverse et du nombre de caractères dans cle, nous devons leur soustraire 32 puisque nous ne considérons pas les 32 premiers caractères de la table ASCII dans le cadre de notre alphabet.

Aussi, nous devons nous assurer que la valeur de la clé est comprise entre 0 et 94 exclu, d'où (cle % 94).

Ce calcul peut néanmoins nous mener à des valeurs négatives. Ainsi, l'opération modulo qui suit n'aurait aucun effet sur le calcul. C'est pourquoi nous rajoutons 94 à notre résultat intermédiaire avant d'effectuer l'opération modulo. Ceci n'altérera pas le résultat final car 94 modulo 94 vaut 0.

Reprenons notre exemple où nous avons chiffré la lettre z de valeur 90 (décalée de 32 par rapport au tableau ASCII d'origine) avec la clé de 10. Le caractère chiffré obtenu était de valeur 6 (38 dans la table ASCII d'origine et lorsque tapé sur le clavier). Pour déchiffrer, nous faison donc le calcul suivant dans notre programme :

texte_clair[i] = (texte_chiffre[i] - 32 - (cle % 94) + 94) % 94;
texte_clair[i] = (38 - 32 - (10 % 94) + 94) % 94;
texte_clair[i] = (6 - 10 + 94) % 94;
texte_clair[i] = (-4 + 94) % 94;
texte_clair[i] = 90 % 94;
texte_clair[i] = 90;

Nous obtenons 90 qui est bien compris entre 0 et 94. En rajoutant 32, nous retrouvons bien 122, le caractère z dans la table ASCII que nous avons chiffré au départ.

Enfin, nous avons besoin d'une fonction d'affichage. Puisque nous travaillons avec une table ASCII décalée, de 32 caractères, nous ne pouvons pas utiliser printf tout simplement. Notre fonction afficher_texte redécale les caractères de la chaîne texte de 32 à droite afin de retrouver un affichage correct à l'écran. Le paramètre longueur spécifie le nombre de caractères de texte à afficher.

void afficher_texte(const char texte[], size_t longueur) {
  size_t i;

  for(i = 0; i < longueur; i++) {
    printf("%c", texte[i] + 32);
  }

  printf("\n");

  return;
}

Nous en arrivons finalement à notre fonction principale main où nous déclarons deux chaînes de caractères : chaine_chiffree et chaine_claire. Puis, deux variables de type caractère reponse et cle. La variable longueur contiendra la longueur effective du texte à traiter.

int main(void) {
  char texte_initial[LONGUEUR_MAX], texte_converti[LONGUEUR_MAX];
  char reponse, cle;
  size_t longueur;

Nous pouvons maintenant demander à l'utilisateur de choisir entre l'opération de chiffrement et l'opération de déchiffrement. Un seul caractère est attendu en réponse : C ou c pour chiffrement et D ou d pour déchiffrement.

  printf("Souhaitez-vous chiffrer ou déchiffrer [CcDd] ?\n");
  scanf(" %c", &reponse);

Ensuite, nous demandons à l'utilisateur de saisir la clé. Notons que %hhd dans scanf signifie, que la valeur attendue est un nombre entier correspondant au type de caractère signé char.

L'appel à la fonction getchar() nous permet de consommer le retour à la ligne laissé dans le tampon d'entrée par l'appel précédent à scanf.

  printf("Saisissez la clé : ");
  scanf(" %hhd", &cle);

  getchar();

Si le choix de l'utilisateur est l'opération de chiffrement, nous lui demandons de saisir le texte à chiffrer que nous sauvegardons dans la chaîne de caractère chaine_chiffree.

  switch(reponse) {
    case 'C':
    case 'c':
      printf("Saisissez du texte à chiffrer : ");
      fgets(chaine_claire, LONGUEUR_MAX, stdin);

Avant d'appeler la fonction de chiffrement et d'afficher le resultat avec notre propre fonction d'affichage afficher_texte, nous déterminons le nombre de caractères du texte entré par l'utilisateur et enlevons le saut à la ligne en dernière position de la chaîne correspondante laissé par fgets. Ainsi, le nombre de caractères de la chaîne diminue de 1, ce que nous mettons à jour avec l'opération --longueur.

      longueur = strnlen(chaine_claire, LONGUEUR_MAX);

      chaine_claire[--longueur] = '\0';

      printf("Voici le résultat du chiffrement :\n");
      chiffrer(chaine_claire, chaine_chiffree, longueur, cle);
      afficher_texte(chaine_chiffree, longueur);
      break;

Le comportement du programme en cas de déchiffrement est analogue.

    case 'D':
    case 'd':
      printf("Saisissez du texte à déchiffrer : ");
      fgets(chaine_chiffree, LONGUEUR_MAX, stdin);

      longueur = strnlen(chaine_chiffree, LONGUEUR_MAX);

      chaine_chiffree[--longueur] = '\0';

      printf("Voici le résultat du déchiffrement :\n");
      dechiffrer(chaine_chiffree, chaine_claire, longueur, cle);
      afficher_texte(chaine_claire, longueur);
      break;

En cas de réponse non reconnue de la part de l'utilisateur, nous afficheons un message d'erreur et terminons le programme en retournant avec le code 1. Sinon, nous terminons bien en retournant le code 0.

    default:
      printf("Réponse '%c' non reconnue !\n", reponse);
      return 1;
  }

  return 0;
}

Voir l'intégrale de la correction dans le fichier chiffrement-de-cesar.c prêt à compiler et exécuter.

5.5.4 INTERMÉDIAIRE Recherche de mots

5.5.4.1 Énoncé

Écrivez un programme qui demande à l'utilisateur d'entrer un texte puis un mot à rechercher dans ce dernier.

Si le mot se trouve dans le texte, le programme affiche un message qui le confirme. Sinon une réponse négative devra être affichée.

Votre programme devra produire la sortie similaire à celle dans l'exemple ci-dessous.

Saisissez du texte : Bonjour les amis !
Saisissez le mot à rechercher dans le texte : amis

Le mot 'amis' se trouve bien dans le texte.

Pour éteindre votre programme, vous pouvez faire en sorte que le nombre total de fois dont le mot se trouve dans le texte soit compté et affiché également si le mot s'y trouve bien sûr (voir un exemple ci-dessous).

Saisissez du texte : Bonjour vous, les amis ! Comment allez-vous ?
Saisissez le mot à rechercher dans le texte : vous

Le mot 'vous' se trouve bien dans le texte (2 fois).
5.5.4.2 Corrigé

Nous commenceons par demander à l'utilisateur d'entrer du texte et le mot à rechercher que nous sauvegardons dans les chaînes de caractères déclarées pour cet effet phrase et mot dont la capacité maximale est de 4 096 caractères.

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

int main(void) {
  char phrase[4096], mot[4096];
  size_t i, j, longueur_phrase, longueur_mot;
  int trouve, occurences;

  printf("Saisissez du texte : ");
  fgets(phrase, 4096, stdin);

  printf("Saisissez le mot ou l'expression à rechercher : ");
  fgets(mot, 4096, stdin);

Ensuite, nous calculons la longueur du texte ainsi que la longueur du mot à rechercher. Nous enlevons également le saut à la ligne finale dans les deux cas laissé par la fonction fgets tout en diminuant les longueurs calculées de 1 en conséquence.

  longueur_phrase = strnlen(phrase, 4096);
  longueur_mot = strnlen(mot, 4096);

  phrase[--longueur_phrase] = '\0';
  mot[--longueur_mot] = '\0';

Notre programme parcourt le texte entré caractère par caractère et à partir de chaque position il compare le sous-ensemble correspondant du texte avec le mot à rechercher. Si le mot est trouvé, le nombre d'occurences augmente de 1. Sinon, la comparaison reprend à part du caractère suivant du texte.

La condition à l'intérieur de la boucle sur i nous permet de nous assurer que la recherche n'est effectuée que si la longueur du mot ne dépasse pas la longueur du sous-ensemble du texte auquel on compare ce dernier.

  occurences = 0;

  for(i = 0; i < longueur_phrase; i++) {
    trouve = 1;

    if(i + longueur_mot > longueur_phrase) {
      trouve = 0;
    } else {
      for(j = 0; j < longueur_mot; j++) {
        if(mot[j] != phrase[i + j]) {
          trouve = 0;
        }
      }
    }

    if(trouve) {
      occurences++;
    }
  }

Par exemple, prenons le texte « Je suis ici. » et le mot à rechercher « suis ». Au premier tour de la boucle sur i, le programme fait la comparaison du sous-ensemble « Je suis ici. » du texte avec le mot « suis » comme suit :

J e   s u i s   i c i .
s u i s                

Le mot n'a pas encore été trouvé, car les deux ne correspondent pas. Au second tour de le boucle, le programme compare « e suis ici. » avec « suis » :

J e   s u i s   i c i .
  s u i s              

Le mot n'a toujours pas été trouvé. Le programme continue et lorsqu'il arrive au quatrième tour de la boucle sur i, le mot « suis » est trouvé au début du sous-ensemble « suis ici. » du texte considéré :

J e   s u i s   i c i .
      s u i s          

Le programme continue encore pour vérifier s'il y a d'autres occurences du mot « suis » dans le reste du texte. Il sort de la boucle avant que la longueur du mot ne dépasse la longueur du sous-ensemble contre lequel ce dernier est comparé :

J e   s u i s   i c i .
                s u i s

Pour finir, nous affichons une réponse en fonction du nombre d'occurences du mot trouvées dans le texte et terminons le programme.

  switch(occurences) {
    case 0:
      printf("'%s' n'a pas été trouvé dans le texte !\n", mot);
      break;
    case 1:
      printf("1 occurence de '%s' a été trouvée dans le texte.\n", mot);
      break;
    default:
      printf(
        "%d occurences de '%s' ont été trouvées dans le texte.\n",
        occurences,
        mot
      );
  }

  return 0;
}

Voir l'intégrale de la correction dans le fichier recherche-de-mots.c prêt à compiler et exécuter.

5.5.5 INTERMÉDIAIRE Comptage de caractères

5.5.5.1 Énoncé

Écrivez un programme qui demande à l'utilisateur d'entrer une chaîne de caractères puis affiche le nombre d'occurences de chaque caractère de la table ASCII dans cette dernière. Il n'est pas nécessaire d'afficher le nombre d'occurences 0 pour les caractères qui ne sont pas présents dans la chaîne.

Votre programme devra produire la sortie similaire à celle dans l'exemple ci-dessous.

Entrez une chaîne de caractères : Bonjour tout le monde !
B : 1
d : 1
e : 2
j : 1
l : 1
m : 1
n : 2
o : 4
r : 1
t : 2
u : 2
! : 1

Indication : Utiliser un tableau de taille 128 (e. g. char occurences[128]) pour garder la trace du nombre d'occurences de chaque caractère de la table ASCII dans le texte d'entrée.

5.5.5.2 Corrigé

Nous commenceons par demander à l'utilisateur d'entrer du texte pour le comptage de caractères que nous sauvegardons dans la chaînea de caractères phrase déclarée pour cet effet et dont la capacité maximale est de 4 096 caractères.

Nous déclarons également un tableau d'entiers comptant une case pour chaque caractère de la table ASCII qui nous servira pour garder la trace des occurences de chaque caractère dans le texte d'entrée.

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

int main(void) {
  char phrase[4096];
  int occurences[128];
  size_t i, longueur_phrase;
  int c;

  printf("Saisissez du texte : ");
  fgets(phrase, 4096, stdin);

Ensuite, nous calculons la longueur du texte d'entrée. Nous enlevons également le saut à la ligne finale à phrase laissé par la fonction fgets tout en diminuant la longueur calculée de 1 en conséquence.

  longueur_phrase = strnlen(phrase, 4096);
  phrase[--longueur_phrase] = '\0';

Si l'utilisateur ne saisit pas de texte en entrée, le nombre de caractères de phrase est inférieur à 1 et par conséquent nous terminons le programme en affichant un message d'erreur et en renvoyant un code non-zéro.

  if(longueur_phrase < 1) {
    printf("Il n'y a pas de caractères dans le texte !\n");
    return 1;
  }

Avant de commencer à compter, nous devons initialiser le nombre d'occurences de chaque caractère à 0.

  for(i = 0; i < 128; i++) {
    occurences[i] = 0;
  }

Enfin, nous pouvons parcourir le texte d'entrée et pour chacun de ses caractères augmenter le nombre d'occurences en conséquent. Ici, chaque index du tableau occurences correspond à un code de la table ASCII et chaque valeur du tableau correspond au nombre d'occurences du caractère désigné par son index.

  for(i = 0; i < longueur_phrase; i++) {
    occurences[(size_t) phrase[i]]++;
  }

Pour finir, nous parcourons le tableau occurences et affichons le nombre d'occurences pour tout les caractères affichables, entre les valeurs 32 et 127 de la table ASCII, ayant été trouvés dans le texte d'entrée au moins une fois.

  printf("Le texte comporte :\n");

  for(c = 32; c < 127; c++) {
    if(occurences[c] > 0) {
      printf("%d fois '%c'\n", occurences[c], c);
    }
  }

  return 0;
}

Voir l'intégrale de la correction dans le fichier comptage-de-caracteres.c prêt à compiler et exécuter.

5.6 Traitement de fichiers

5.6.1 BASIQUE Recherche de mots dans un fichier

5.6.1.1 Énoncé

Reprenez l'énoncé de l'exercice 5.5.4.1 et modifiez votre programme de sorte qu'il lise le texte d'entrée à partir d'un fichier dont il demandera le chemin d'accès à l'utilisateur.

Votre programme devra produire la sortie similaire à celle dans l'exemple ci-dessous en supposant que le fichier contenu.txt contient les phrases suivantes : « Bonjour vous, les amis ! Comment allez-vous ? ».

Saisissez le chemin d'accès au fichier texte : contenu.txt
Saisissez le mot à rechercher dans le texte : vous

Le mot 'vous' se trouve bien dans le texte (2 fois).
5.6.1.2 Corrigé

Nous commençons de la même façon que dans la correction 5.5.4.2. Seulement, nous considérons en plus la chaîne de caractères chemin dans laquelle nous sauvegardons le chemin du fichier texte d'entrée. La capacité de cette chaîne est de PATH_MAX qui est une macro définie dans limits.h correspodant à la longueur maximale d'un chemin d'accès.

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

int main(void) {
  char phrase[4096], mot[4096], chemin[PATH_MAX];
  size_t i, j, longueur_phrase, longueur_mot, longueur_chemin;
  int trouve, occurences;

  printf("Saisissez le chemin d'accès au fichier texte : ");
  fgets(chemin, PATH_MAX, stdin);

  printf("Saisissez le mot ou l'expression à rechercher : ");
  fgets(mot, 4096, stdin);

  longueur_mot = strnlen(mot, 4096);
  longueur_chemin = strnlen(chemin, PATH_MAX);

  mot[--longueur_mot] = '\0';
  chemin[--longueur_chemin] = '\0';

Nous passons ensuite à la lecture du fichier pointé par chemin. Pour cela, nous déclarons un tableau de caractère supplémentaire qui nous servira de tampon de lecture pour la fonction de lecture fread que nous appelons en boucle pour lire la totalité du fichier par morceaux de la taille du tampon.

Mais avant tout, il nous faut ouvrir le fichier texte en lecture.

  FILE * flux = fopen(chemin, "r");

  char tampon[256];

  while(fread(tampon, 1, 256, flux) != 0) {
    strncat(phrase, tampon, 256);
  }

  fclose(flux);

  longueur_phrase = strnlen(phrase, 4096);
  phrase[--longueur_phrase] = '\0';

Après la fermeture du fichier d'entrée, le reste du code source reste le même.

  occurences = 0;

  for(i = 0; i < longueur_phrase; i++) {
    trouve = 1;

    if(i + longueur_mot > longueur_phrase) {
      trouve = 0;
    } else {
      for(j = 0; j < longueur_mot; j++) {
        if(mot[j] != phrase[i + j]) {
          trouve = 0;
        }
      }
    }

    if(trouve) {
      occurences++;
    }
  }

  switch(occurences) {
    case 0:
      printf("'%s' n'a pas été trouvé dans le texte !\n", mot);
      break;
    case 1:
      printf("1 occurence de '%s' a été trouvée dans le texte.\n", mot);
      break;
    default:
      printf(
        "%d occurences de '%s' ont été trouvées dans le texte.\n",
        occurences,
        mot
      );
  }

  return 0;
}

Voir l'intégrale de la correction dans le fichier recherche-de-mots-dans-un-fichier.c prêt à compiler et exécuter.

5.6.2 BASIQUE Écriture formatée

5.6.2.1 Énoncé

Écrivez un programme qui demande à l'utilisateur son nom, puis enregistre la phrase suivante dans le fichier nommé presentation.txt : « Bonjour ! Je m'appelle <nom> » où <nom> est le nom entré par l'utilisateur.

Votre programme devra produire la sortie similaire à celle dans l'exemple ci-dessous.

Entrez votre nom : Marek

Le fichier presentation.txt correspondant devrait contenir :

Bonjour ! Je m'appelle Marek.
5.6.2.2 Corrigé

Au début, nous demandons à l'utilisateur d'entrer son nom que nous sauvegardons dans la chaîne de caractères nom de capacité 128.

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

int main(void) {
  char nom[128];
  FILE * fichier;

  printf("Entrez votre nom : ");
  scanf(" %s", nom);

Ensuite, nous ouvrons le fichier de sortie presentation.txt en mode d'écriture.

  fichier = fopen("presentation.txt", "w");

Pour écrire dans le fichier nous utilisons la fonction fprintf, identique à printf mais permettant d'écrire dans un fichier au lieu d'écrire sur le terminal.

Finalement, nous fermons le fichier et terminons le programme.

  fprintf(fichier, "Bonjour !\nJe m'appelle %s.\n", nom);

  fclose(fichier);

  return 0;
}

Voir l'intégrale de la correction dans le fichier ecriture-formatee.c prêt à compiler et exécuter.

5.6.3 INTERMÉDIAIRE Lecture formatée

5.6.3.1 Énoncé

Écrivez un programme pour lire un fichier de texte formaté contenant une liste de personnes comprenant leurs noms et leurs âges. Le programme demandera le chemin d'accès au fichier d'entrée à l'utilisateur.

Le fichier d'entrée devra avoir le format tel que dans l'exemple ci-dessous. Notez que les valeurs dans les lignes sont séparées en utilisant un caractère de tabulation TAB (désigné par \t en C).

Marek	24
John	37
Jane	19
George	85

Supposant que l'exemple précédent constitue le fichier du nom donnees.txt, votre programme devra produire la sortie similaire à celle dans l'exemple ci-dessous.

Saisissez le chemin vers le fichier de données : donnees.txt

NOM    ÂGE
Marek  24
John   37
Jane   19
George 85
5.6.3.2 Corrigé

Nous commençons par demander à l'utilisateur d'entrer le chemin d'accès au fichier de données que nous ouvrons en lecture avec la fonction fopen.

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

int main(void) {
  char chemin[PATH_MAX];
  FILE * fichier;

  printf("Saisissez le chemin vers le fichier de données : ");
  scanf(" %s", chemin);

  printf("NOM\tÂGE\n");

  fichier = fopen(chemin, "r");

Puis, nous utilisons la fonction fscanf, identique à scanf mais permettant de lire dans un fichier, en boucle pour lire ligne par ligne le fichier de données et afficher sont contenu sous forme d'un tableau rudimentaire.

Ici, nom et age servent de tampons de lecture pour les valeurs d'une ligne du fichier de données dans la boucle.

À la fin, nous fermons le fichier et terminons le programme.

  char nom[128];
  int age;

  while(fscanf(fichier, "%s\t%d", nom, &age) != EOF) {
    printf("%s\t%d\n", nom, age);
  }

  fclose(fichier);

  return 0;
}

Voir l'intégrale de la correction dans le fichier lecture-formatee.c prêt à compiler et exécuter.

Date: 2019/2020

Auteur: Marek Felsoci

Email: marek.felsoci@inria.fr

Validate