Licence CC 0

Manipulations basiques des entrées/sorties

Dernière mise à jour :

Durant l’exécution d’un programme, le processeur a besoin de communiquer avec le reste du matériel. Ces échanges d’informations sont les entrées et les sorties (ou input et output pour les anglophones), souvent abrégées E/S (ou I/O par les anglophones).

Les entrées permettent de recevoir une donnée en provenance de certains périphériques. Les données fournies par ces entrées peuvent être une information envoyée par le disque dur, la carte réseau, le clavier, la souris, un CD, un écran tactile, bref par n’importe quel périphérique. Par exemple, notre clavier va transmettre des informations sur les touches enfoncées au processeur : notre clavier est donc une entrée.

À l’inverse, les sorties vont transmettre des données vers ces périphériques. On pourrait citer l’exemple de l’écran : notre ordinateur lui envoie des informations pour qu’elles soient affichées.

Dans ce chapitre, nous allons apprendre différentes fonctions fournies par le langage C qui vont nous permettre d’envoyer des informations vers nos sorties et d’en recevoir depuis nos entrées. Vous saurez ainsi comment demander à un utilisateur de fournir une information au clavier et comment afficher quelque chose sur la console.

Les sorties

Intéressons-nous dans un premier temps aux sorties. Afin d’afficher du texte, nous avons besoin d’une fonction.

Une fonction est un morceau de code qui a un but, une fonction particulière et qui peut être appelée à l’aide d’une référence, le plus souvent le nom de cette fonction (comme pour une variable, finalement). En l’occurrence, nous allons utiliser une fonction qui a pour objectif d’afficher du texte dans la console : la fonction printf().

Première approche

Un exemple valant mieux qu’un long discours, voici un premier exemple.

1
2
3
4
5
6
7
8
#include <stdio.h>


int main(void)
{
    printf("Bonjour tout le monde !\n");
    return 0;
}
1
Bonjour tout le monde !

Deux remarques au sujet de ce code.

1
#include <stdio.h>

Il s’agit d’une directive du préprocesseur, facilement reconnaissable car elles commencent toutes par le symbole #. Celle-ci sert à inclure un fichier (« stdio.h ») qui contient les références de différentes fonctions d’entrée et sortie (« stdio » est une abbréviation pour « Standard input output », soit « Entrée-sortie standard »).

Un fichier se terminant par l’extension « .h » est appelé un fichier d’en-tête (header en anglais) et fait partie avec d’autre d’un ensemble plus large appelée la bibliothèque standard (« standard » car elle est prévue par la norme1).

1
printf("Bonjour tout le monde !\n");

Ici, nous appelons la fonction printf() (un appel de fonction est toujours suivi d’un groupe de parenthèses) avec comme argument (ce qu’il y a entre les parenthèses de l’appel) un texte (il s’agit plus précisément d’une chaîne de caractères, qui est toujours comprise entre deux guillemets double). Le \n est un caractère spécial qui représente un retour à la ligne, cela est plus commode pour l’affichage.

Le reste devrait vous être familier.

Les formats

Bien, nous savons maintenant afficher une phrase, mais ce serait quand même mieux de pouvoir voir les valeurs de nos variables. Comment faire ? bien, pour y parvenir, la fonction printf() met à notre disposition des formats. Ceux-ci sont en fait des sortes de repères au sein d’un texte qui indique à printf() que la valeur d’une variable est attendue à cet endroit. Voici un exemple pour une variable de type int.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include <stdio.h>


int main(void)
{
    int variable = 20;

    printf("%d\n", variable);
    return 0;
}
1
20

Nous pouvons voir que le texte de l’exemple précédent a été remplacé par %d, seul le \n a été conservé. Un format commence toujours par le symbole % et est suivi par une ou plusieurs lettres qui indiquent le type de données que nous souhaitons voir afficher. Cette suite de lettre est appelée un indicateur de conversion. En voici une liste non exhaustive2.

Type Indicateur(s) de conversion
char c, d (ou i)
short d (ou i)
int d (ou i)
long ld (ou li)
unsigned char u, x (ou X) ou o
unsigned short u, x (ou X) ou o
unsigned int u, x (ou X) ou o
unsigned long lu, lx (ou lX) ou lo
float f, e (ou E) ou g (ou G)
double f, e (ou E) ou g (ou G)
long double Lf, Le (ou LE) ou Lg (ou LG)

Notez que pour le type char, l’indicateur est soit c, soit d (ou i). Cela dépend si vous l’utilisez pour contenir un caractère ou un entier. Également, notez que les indicateurs de conversions sont identiques pour les types char (s’il stocke un entier), short et int (pareil pour leurs équivalents non signés) ainsi que pour les types float et double.

Les indicateurs x, X et o permettent d’afficher un nombre en représentation hexadécimale ou octale (l’indicateur x affiche les lettres en minuscules alors que l’indicateur X les affiches en majuscules).

Les indicateurs f, e et g permettent quant à eux d’afficher un nombre flottant. L’indicateur f affiche un nombre en notation simple avec, par défaut, six décimales ; l’indicateur e affiche un nombre flottant en notation scientifique (l’indicateur e utilise la lettre « e » avant l’exposant alors que l’indicateur « E » emploie la lettre « E ») et l’indicateur g choisi quant à lui entre les deux notations précédentes suivant le nombre fourni et supprime la partie fractionnaire si elle est nulle de sorte que l’écriture soit concise (la différence entre les indicateurs g et G est identique à celle entre les indicateurs e et E).

Allez, un petit exemple pour reprendre tout cela et retravailler le chapitre précédent par la même occasion.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>


int main(void)
{
    char z = 'z';
    char a = 10;
    unsigned short b = 20;
    int c = 30;
    long d = 40;
    float e = 50.;
    double f = 60.0;
    long double g = 70.0;

    printf("%c\n", z);
    printf("%d\n", a);
    printf("%u\n", b);
    printf("%o\n", b);
    printf("%x\n", b);
    printf("%d\n", c);
    printf("%li\n", d);
    printf("%f\n", e);
    printf("%e\n", f);
    g = 80.0;
    printf("%Lg\n", g);
    return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
z
10
20
24
14
30
40
50.000000
6.000000e+01
80

Si vous souhaitez afficher le caractère % vous devez le doubler : %%.

Précision des nombres flottants

Vous avez peut-être remarquer que lorsqu’un flottant est affiché avec le format f, il y a un certain nombre de zéros qui suivent (par défaut six) et ce, peu importe qu’ils soient utiles ou non. Afin d’en supprimer certains, vous pouvez spécifier une précision. Celle-ci correspond au nombre de chiffre suivant la virgule qui seront affichés. Elle prend la forme d’un point suivi par un nombre : la quantité de chiffres qu’il y aura derrière la virgule.

1
2
3
double x = 42.42734;

printf("%.2f", x);
1
42.43

Les caractères spéciaux

Dans certains cas, nous souhaitons obtenir un résultat à l’affichage (saut de ligne, une tabulation, un retour chariot, etc.). Cependant, ils ne sont pas particulièrement pratiques à insérer dans une chaîne de caractères. Aussi, le C nous permet de le faire en utilisant une séquence d’échappement. Il s’agit en fait d’une suite de caractères commençant par le symbole \ et suivie d’une lettre. En voici une liste non exhaustive.

Séquence d’échappement Signification
\a Caractère d’appel
\b Espacement arrière
\f Saut de page
\n Saut de ligne
\r Retour chariot
\t Tabulation horizontale
\v Tabulation verticale
\" Le symbole « " »
\\ Le symbole « \ » lui-même

En général, vous n’utiliserez que le saut de ligne, la tabulation horizontale et de temps à autre le retour chariot, les autres n’ont quasiment plus d’intérêt. Un petit exemple pour illustrer leurs effets.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include <stdio.h>


int main(void)
{
    printf("Quelques sauts de ligne\n\n\n");
    printf("\tIl y a une tabulation avant moi !\n");
    printf("Je voulais dire que...\r");
    printf("Hey ! Vous pourriez me laisser parler !\n");
    return 0;
}
1
2
3
4
5
Quelques sauts de ligne


        Il y a une tabulation avant moi !
Hey ! Vous pourriez me laisser parler !

Le retour chariot provoque un retour au début de la ligne courante. Ainsi, il est possible d’écrire par-dessus un texte affiché.

Sur plusieurs lignes

Notez qu’il est possible d’écrire un long texte sans appeler plusieurs fois la fonction printf(). Pour ce faire, il suffit de le diviser en plusieurs chaînes de caractères.

1
2
3
4
5
6
7
8
9
#include <stdio.h>

int main(void)
{
    printf("Texte écrit sur plusieurs "
           "lignes dans le code source "
           "mais sur une seule dans la console.\n");
    return 0;
}
1
Texte écrit sur plusieurs lignes dans le code source mais sur une seule dans la console.

  1. Programming Language C, X3J11/88-090, § 4, Library. 

  2. Pour le type long long introduit en C99, les indicateurs de conversions sont lld et llu. Il en va de même pour scanf()

Interagir avec l'utilisateur

Maintenant que nous savons déclarer, utiliser et même afficher des variables, nous sommes fin prêts pour interagir avec l’utilisateur. En effet, jusqu’à maintenant, nous nous sommes contentés d’afficher des informations. Nous allons à présent voir comment en récupérer grâce à la fonction scanf(), dont l’utilisation est assez semblable à printf().

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#include <stdio.h>


int main(void)
{
    int age;

    printf("Quel âge avez-vous ? ");
    scanf("%d", &age);
    printf("Vous avez %d an(s)\n", age);
    return 0;
}
1
2
Quel age avez-vous ? 15
Vous avez 15 an(s).

Comme vous le voyez, l’appel à scanf() ressemble très fort à celui de printf() mise à part l’absence du caractère spécial \n (qui n’a pas d’intérêt puisque nous récupérons des informations) et le symbole &.

À son sujet, souvenez-vous de la brève explication sur la mémoire au début du chapitre précédent. Celle-ci fonctionne comme une armoire avec des tiroirs (les adresses mémoires) et des objets dans ces tiroirs (nos variables). La fonction scanf() a besoin de connaitre l’emplacement en mémoire de nos variables afin de les modifier. Afin d’effectuer cette opération, nous utilisons le symbole & (qui est en fait un opérateur que nous verrons en détail plus tard). Ce concept de transmission d’adresses mémoires est un petit peu difficile à comprendre au début, mais ne vous inquiétez pas, vous aurez l’occasion de bien revoir tout cela en profondeur dans le chapitre traîtant des pointeurs.

Ici, scanf() attend patiemment que l’utilisateur saisisse un nombre au clavier afin de modifier la valeur de la variable age. On dit que c’est une fonction bloquante, car elle suspend l’exécution du programme tant que l’utilisateur n’a rien entré.

Pour ce qui est des indicateurs de conversions, ils sont un peu différents de ceux de printf().

Type Indicateur(s) de conversion
char c
short hd ou hi
int d ou i
long ld ou li
unsigned short hu, hx ou ho
unsigned int u, x ou o
unsigned long lu, lx ou lo
float f
double lf
long double Lf

Faites bien attention aux différences ! Si vous utilisez le mauvais format, le résultat ne sera pas celui que vous attendez. Les changements concernent les types char, short et double.

Notez que l’indicateur c ne peut être employé que pour récupérer un caractère et non un nombre.

Remarquez également qu’il n’y a plus qu’un seul indicateur pour récupérer un nombre hexadécimal : x (l’utilisation de lettres majuscules ou minuscules n’a pas d’importance).

En passant, sachez qu’il est possible de lire plusieurs entrées en même temps, par exemple comme ceci.

1
2
3
4
int x, y;

scanf("%d %d", &x, &y);
printf("x = %d | y = %d\n", x, y);

L’utilisateur a deux possibilités, soit insérer un (ou plusieurs) espace(s) entre les valeurs, soit insérer un (ou plusieurs) retour(s) à la ligne entre les valeurs.

1
2
3
14
6
x = 14 | y = 6
1
2
14 6
x = 14 | y = 6

La fonction scanf() est en apparence simple (oui, en apparence), mais son utilisation peut devenir très complexe lorsqu’il est nécessaire de vérifier les entrées de l’utilisateur (entre autres). Cependant, à votre niveau, vous ne pouvez pas encore effectuer de telles vérifications. Ce n’est toutefois pas très grave, nous verrons cela en temps voulu. ;)


Maintenant, vous êtes capable de communiquer avec l’utilisateur. Cependant, nos actions sont encore un peu limitées. Nous verrons dans les prochains chapitres comment mieux interagir avec l’utilisateur.