Après avoir appris à transmettre des messages vers l'écran, découvrons comment rendre nos programmes interactifs en lisant des données saisies au clavier par l'utilisateur.
En langage C, la lecture sur l'entrée standard (stdin) repose principalement sur la fonction scanf() et la fonction getchar(), toutes deux déclarées dans <stdio.h>.
1. La fonction scanf() et le rôle vital de l'opérateur &#
La fonction scanf() (scan formatted) analyse le flux de saisie au clavier et stocke la valeur convertie dans une case mémoire réservée à une variable.
#include <stdio.h>
int main(void)
{
int age = 0;
printf("Entrez votre age : ");
// L'esperluette & indique l'adresse mémoire de la variable 'age'
scanf("%d", &age);
printf("Vous avez declare avoir %d ans.\n", age);
return 0;
}
Pourquoi l'esperluette & est-elle obligatoire ?#
En C, lorsqu'une variable est passée en paramètre à une fonction sans préfixe, la fonction ne reçoit qu'une copie de sa valeur. Si scanf() travaillait sur une copie, elle modifierait cette copie temporaire et votre variable originale resterait inchangée !
En préfixant le nom de la variable par & (l'opérateur d'adresse), vous transmettez à scanf() l'adresse de la case mémoire où réside la variable. La fonction peut ainsi aller directement écrire la valeur saisie dans la mémoire vive.
[!WARNING] Oublier le symbole
&devant une variable scalaire dansscanf()est l'erreur numéro un des débutants en C : le programme compilera parfois avec un simple avertissement mais plantera immédiatement à l'exécution avec une redoutable erreur de segmentation (Segmentation Fault).
2. Spécificateurs de format pour scanf()#
Attention à la subtilité fondamentale entre float et double lors de la lecture :
| Type attendu | Spécificateur scanf |
Syntaxe d'appel |
|---|---|---|
int |
%d |
scanf("%d", &entier); |
float |
%f |
scanf("%f", &flottant); |
double |
%lf (long float) |
scanf("%lf", &flottant_double); |
char |
%c |
scanf("%c", &caractere); |
char[] (chaîne) |
%s (sans espaces) |
scanf("%29s", tableau_char); (pas de & car le nom d'un tableau est déjà une adresse) |
3. Saisie d'un caractère avec getchar()#
Pour lire un caractère unique au clavier, la fonction getchar() est une alternative élégante et directe :
#include <stdio.h>
int main(void)
{
printf("Entrez votre initiale : ");
char initiale = getchar();
printf("Initiale enregistree : '%c'\n", initiale);
return 0;
}
4. Le piège classique du tampon d'entrée (Buffer)#
Lorsque vous tapez un nombre au clavier (par exemple 25) puis appuyez sur Entrée, vous envoyez deux éléments dans le tampon de mémoire du clavier :
1. Le nombre 25
2. Le caractère invisible de saut de ligne \n produit par la touche Entrée.
scanf("%d", ...) consomme le nombre 25, mais laisse traîner le \n dans le tampon ! Si vous tentez immédiatement après de lire un caractère avec scanf("%c", ...) ou getchar(), la fonction lira instantanément le \n résiduel sans attendre que l'utilisateur n'ait eu le temps de taper quoi que ce soit.
#include <stdio.h>
int main(void)
{
int annee;
char mention;
printf("Annee d'etudes (1 a 5) : ");
scanf("%d", &annee);
// ASTUCE : L'espace avant %c force scanf a ignorer tous les blancs et le '\n' residuel
printf("Mention souhaitee (A/B/C) : ");
scanf(" %c", &mention);
printf("Resultat : Annee %d | Mention %c\n", annee, mention);
return 0;
}
Méthode universelle pour vider le tampon d'entrée#
Pour nettoyer rigoureusement le tampon après une saisie, on consomme tous les caractères restants jusqu'au saut de ligne :
void ViderBuffer(void)
{
int c;
while ((c = getchar()) != '\n' && c != EOF)
{
// On jette les caractères résiduels
}
}
5. Saisir des phrases avec espaces : la supériorité de fgets()#
L'instruction scanf("%s", texte) s'arrête au premier espace rencontré. Pour lire une ligne complète (par exemple le prénom et le nom d'un étudiant avec espaces), on utilise fgets() :
#include <stdio.h>
#include <string.h>
#define TAILLE_MAX 50
int main(void)
{
char nom_complet[TAILLE_MAX];
printf("Entrez votre nom et prenom : ");
// Lit jusqu'à TAILLE_MAX-1 caractères depuis l'entrée standard stdin
if (fgets(nom_complet, sizeof(nom_complet), stdin) != NULL)
{
// Supprime le saut de ligne final éventuel capté par fgets
nom_complet[strcspn(nom_complet, "\n")] = '\0';
printf("Bienvenue, %s !\n", nom_complet);
}
return 0;
}
[!NOTE] La fonction historique
gets()a été officiellement bannie de la norme C (supprimée depuis C11) car elle est incapable de limiter la taille de la saisie, provoquant de gravissimes failles de dépassement de tampon (buffer overflow). Utilisez toujoursfgets()!
6. Mise en pratique : Calculateur de moyenne#
Énoncé : Concevez un programme qui demande à un étudiant son nom, son âge et deux notes d'examens (coefficients 2 et 3), puis calcule et affiche sa moyenne pondérée avec deux décimales.
??? tip "Solution complète"
#include <stdio.h>
int main(void)
{
int age;
float note1, note2;
const int coef1 = 2;
const int coef2 = 3;
printf("--- FORMULAIRE D'EVALUATION ACADEMIQUE ---\n");
printf("Age de l'etudiant : ");
scanf("%d", &age);
printf("Note d'examen 1 (sur 20) : ");
scanf("%f", ¬e1);
printf("Note d'examen 2 (sur 20) : ");
scanf("%f", ¬e2);
float moyenne = (note1 * coef1 + note2 * coef2) / (float)(coef1 + coef2);
printf("\n------------------------------------------\n");
printf("Etudiant age de %d ans\n", age);
printf("Moyenne ponderee : %.2f / 20\n", moyenne);
if (moyenne >= 10.0f)
{
printf("Decision : ADMIS(E)\n");
}
else
{
printf("Decision : AJOURNE(E)\n");
}
printf("------------------------------------------\n");
return 0;
}
Vous savez désormais communiquer dans les deux sens avec l'utilisateur. Approfondissons maintenant la gestion de la mémoire avec les variables, types fondamentaux et constantes en langage C.
Commentaires