Le langage C
Deuxième partie

Par :
Guilhem de Wailly (gdw@erian-concept.com)

Résumé
Dans cette série d'articles, nous présentons le langage C. Il ne s'agit pas de réécrire les ouvrages de référence donnés en annexe, mais de donner, au travers du C, une méthode de programmation basée sur la notion d'interface.
Au fur et à mesure de notre progression, nous décrirons les éléments indispensables du langage et conduirons le lecteur à consulter les ouvrages de références. Le but poursuivit est clairement de parvenir à construire des programmes de manière segmentée.
Introduction
Dans l'article précédent, nous avons découvert le langage C et le compilateur. Nous avons créé notre premier programme, le fameux hello World!.
Nous avons également vu comment écrire la fonction principale d'un programme C, comment déclarer une variable, l'initialiser et l'utiliser. Nous avons aussi parlé de l'affichage à l'écran.
Nous allons examiner plus en détails les fonctions d'entrée / sortie de base, l'écriture des commentaires, des itérations et des expressions de test.
Entrée / sorties console
Dans cette section, nous allons un peu développer les entrées/sorties sur console. Malheureusement, les entrées / sorties en C font appel à des fonctions qui ne sont pas triviales ; ce sont des fonctions acceptant un nombre d'argument variable. Or elles sont indispensables dès que l'on souhaite écrire des programmes d'exemple.
Nous allons nous attacher à décrire les deux principales fonctions d'entrée / sortie en donnant une explication sommaire de leur fonctionnement. Plus tard, lorsque nous aurons plus d'expérience en C, nous reviendrons sur ces fonctions plus en détails, quitte à les réécrire partiellement.
Affichage
La principale fonction qui permet d'afficher des messages à l'écran est printf (il existe d'autres moyens plus primitifs de manipuler l'écran, mais printf est le plus immédiat).
C'est une fonction dont le nombre d'argument est variable. Le premier argument est obligatoirement une chaîne de caractère appelée chaîne de formatage.
Cette chaîne est affichée telle quelle, mis à part un certain nombre de séquences de caractère qui modifient l'affichage :
•\n est remplacé par un saut de ligne
•\t est remplacé par une tabulation
•\b est remplacé par un retour arrière ; si le curseur est en début de ligne, \b n'a aucun effet ; sinon, le caractère avant le curseur est effacé si le curseur est déplacé d'un caractère vers la gauche ;
•\" est replacé par un guillemet ;
•%c est remplacé par l'argument supplémentaire correspondant lu comme un caractère ; attention contrôle de type n'est effectué sur les arguments supplémentaires ;
•%d : argument entier ;
•%f : argument réel ;
•%p : argument pointeur (nous en parlerons plus tard) ;
•%s : argument chaîne de caractère ;
Nous aurons par exemple :
printf ("bonjour\ntous le monde!\n");
--> bonjour
tout le monde!
printf ("caractère %c, entier %d\n",
        'e', 123);
--> caractère e, entier 123
printf ("réel %f, chaîne %s\n", 123.0, "hello");
--> réel 123.0, chaîne hello
Le langage C est très permissif : il effectue peu de contrôles.
Par exemple :
printf ("rien\n", 1, 2, 3, 4);
--> rien
Dans cet exemple, des arguments supplémentaires sont donnés à la fonction, mais ils sont ignorés car ils ne correspondent à aucun %.
printf ("aléatoire %d\n");
--> aléatoire 9566758
Là, le format spécifie un argument lu comme un entier, mais aucune valeur n'est donnée ; la valeur affichée sera aléatoire et différente à chaque appel.
printf ("aléatoire %s\n");
--> Segmentation error. Core Dumped
Ici, la valeur attendue est une chaîne de caractère, qui est une donnée complexe. La valeur aléatoire a peu de chance de correspondre à une chaîne de caractère en mémoire. Il a donc une erreur mémoire.
printf ("code ascii de '%c' = %d\n", 'a', 'a');
--> Code ascii de 'e' = 64
Enfin, nous affichons un caractère comme un entier ; la valeur affichée correspond au nombre entier qui sert à coder le caractère dans la mémoire. Cette valeur dépend de la machine utilisée et du système d'exploitation. Avec Unix, il y a de grande chance que cela corresponde au code ASCII.
Comme on le remarque, C effectue peu de contrôle. Il responsabilise le programmeur.
Lecture
La principale fonction de lecture de C est scanf.
C'est aussi une fonction ayant un nombre d'argument variable dont le premier est obligatoirement une chaîne de format. Les caractères de cette chaîne sont les caractères devant être lus. Dans cette chaîne, les séquences % doivent correspondre à des variables qui reçoivent les valeurs lues.
Ces variables doivent être préfixées par le caractère & (on verra plus tard que se sont en fait des adresses).
On aura par exemple :
int a;

printf ("Entrez un entier:\n");
scanf ("%d", & a);
printf ("L'entier lu est %d\n", a);
--> Entrez en entier
123 [ENTER]
L'entier lu est 123

En plaçant des caractères dans le format, cela donne :
int a;

printf ("Entrez un entier);
printf (" préfixé par ");
scanf ("x%d", & a);
printf ("L'entier lu est %d\n", a);
--> Entrez en entier préfixé par x
x123 [ENTER]
L'entier lu est 123
Si on n'introduit pas le caractère x en premier, l'entier ne sera jamais lu ; en fait, la fonction scanf reste bloquée jusqu'à ce qu'elle rencontre le caractère x, suivi d'un entier.
Programme
Nous allons utiliser nos connaissances sur les entrées / sorties pour écrire un programme qui calcule la somme de deux nombres.
Plaçons le code suivant dans le fichier somme.c :
#include <stdio.h>

void main (void) {
  int a, b, somme;

  /* lecture du premier entier */
  printf ("Premier entier:\n");
  scanf ("%d", & a);

  /* lecture du second entier /
  printf ("Second entier:\n");
  scanf ("%d", & b);

  /* calcul de leur somme /
  somme = a + b;

  /* affichage */
  printf ("%d + %d = %d\n", a, b, somme);
}
Compilons le programme, et exécutons-le :

$ gcc somme.c o somme
$ ./somme
--> Premier nombre:
123 [ENTER]
Second nombre:
456 [ENTER]
123 + 456 = 579
Utilisez maintenant ces programmes avec d'autres entiers. Fonctionne-t-il toujours correctement ?
Itération
Le programme précédent est intéressant, mais un peu pénible à exécuter sur une séquence de nombres. Il serait pratique d'écrire une boucle dans le main afin de permettre la répétition des calculs.
while
Pour cela, il existe le mot-clef while qui s'utilise de la manière suivante :
while (condition) instruction
où condition est une expression. Tant que cette expression retourne un résultat non nul, l'instruction est exécutée. L'instruction est soit une expression simple, soit un bloc d'expressions entre accolades.
Ainsi, notre fonction principale devient :
void main (void) {
 int a, b, somme = 1;
 
 while (somme != 0) {
  /* lecture du premier entier */
  printf ("Premier entier:\n");
  scanf ("%d", & a);

  /* lecture du second entier /
  printf ("Second entier:\n");
  scanf ("%d", & b);

  /* calcul de leur somme /
  somme = a + b;

  / affichage */
  printf ("%d + %d = %d\n",a, b, somme);
 }
}
Pour que la boucle s'arrête, il faut que la somme des deux entiers soit nulle. Nous évitons que ce cas ne se produise dès le démarrage en initialisant somme à 1. Remarquons au passage que les commentaires en C s'écrivent entre /* et */. Ils peuvent tenir sur plusieurs lignes.
Les expressions de tests sont :
•a == b : vrai si a et b sont égaux ;
•a != b : vrai si a et b sont différents ;
•a >= b : vrai si a est plus grand ou égal à b ;
•a > b : vrai si a est plus grand que b ;
•a <= b : vrai si a est plus petit ou égal à b ;
•a < b : vrai si a est plus petit que b ;
•a : vrai si a est non nul ;
Le langage C ne possède pas le type booléen : N'importe quel type de valeur peut jouer ce rôle. La valeur nulle est considérée comme fausse et les autres valeurs sont considérées comme vraies.
do...while

Une autre forme d'itération peut être écrite avec la forme do...while. Elle a la forme :
do instruction while (condition);
Dans ce cas, l'instruction est d'abord exécutée, puis la condition est évaluée. Cette forme correspondrait mieux à nos souhaits pour la fonction principale, évitant ainsi d'initialiser la variable somme :
void main (void) {
 int a, b, somme;

 do {
  /* corps identique */
 } while (somme != 0);
}
for
L'instruction for est la forme la plus générale pour écrire des itérations. Sa syntaxe est la suivante :
for (init; test; post)
expression
L'expression init est exécutée au début de l'itération. Puis le test est évalué et si son résultat est nul, l'itération se termine. Sinon, l'expression est évaluée. Avant de recommencer l'itération, l'expression post est évaluée. L'itération recommence alors par l'évaluation du test.
Il est possible de placer plusieurs instructions séparées par des virgules dans init et post. L'expression peut être un bloc entouré d'accolades. Ces expressions peuvent aussi être vides.
Pour afficher la table de multiplication par 7, nous écririons :
int i, n = 7;
for (i = 0; i <= 10; i = i + 1) {
 printf ("%d x %d = %d\n", i, n, i * n);
}
Pour écrire une boucle infinie, nous entrerions :
for (;;) expression;
Ainsi, l'instruction for laisse complètement le contrôle au programmeur sur la manière d'exécuter l'itération.
L'auteur
Guilhem de Wailly, directeur de la société Erian Concept, partenaire RedHat France, Khéops et Getek:

	Support, formations, configurations, administration, développements Linux.
http://www.erian-concept.com	

Références
Langage C - norme ANSI
Ph. DRIX
Masson
Programmer en C++
S.C. DEWHURST et K.T. STARK
Masson
Le Langage C
B.W. KERNIGHAN et D.M. RITCHIE 
Masson