Avant d’aborder la gestion des caractères en C, il est important de revenir sur le fonctionnement de la lecture clavier en général sur un OS (Operating System ou Système d’exploitation en français). Pour Windows (mais c’est identique sur un MAC ou Linux), chaque appui sur une touche du clavier est capté par le driver de clavier et placé dans un buffer de caractères (mémoire RAM du PC). Par exemple, si l’utilisateur tape sur son clavier 12.3 on trouvera dans le buffer de caractères les codes ASCII des 4 caractères ('1', '2', '.', '3') suivis du code ASCII de la touche Entrée (qui a le code '\n'). Ce fonctionnement est indépendant de l’appel de la fonction scanf puisqu’il est géré par l’OS.
Lors de l’exécution de notre programme, la fonction scanf va aller lire le buffer de caractères et attendre de trouver le code ASCII de la touche Entrée ('\n') ou la touche espace ' '. La fonction scanf est une fonction bloquante (l’exécution du code est bloquée tant que l’utilisateur n’a pas tapé sur la touche Entrée ).
Après appui sur Entrée la fonction scanf va lire le buffer de caractères et encoder la valeur réelle (ou entière) dans la case mémoire de la valeur à lire puis va vider le buffer de caractères (en réalité c’est un pointeur qui gère le buffer).
1* : chaque appui sur les touches du clavier vient remplir le buffer de caractères
2* : la fonction scanf étant bloquante, l'appui sur retour charriot ('\n') vient lancer la routine de lecture du buffer de caractères et encode la variable dans le type spécifié (ici %f donc codage de type float).
En résumé, c’est l’OS qui s’occupe de remplir le buffer de caractères et c’est la fonction scanf (fonction bloquante) qui vient lire le buffer, encoder la valeur à lire et vider le buffer. Il faut appuyer sur la touche Entrée pour débloquer la fonction scanf.
Chaque touche du clavier possède un code sur 8 bits basé sur le code ASCII pour les 128 premiers caractères (lettres minuscules et majuscules sans accent, chiffres et symboles usuels).
Peut-on lire directement les caractères entrés par l’utilisateur ?
La réponse est bien évidemment OUI. Pour lire un caractère au clavier, on utilise la fonction getchar() ou scanf("%c", &c).Ces 2 fonctions ont le même fonctionnement. Elles sont bloquantes, c’est-à-dire qu’elles attendent que l’utilisateur ait tapé sur « Entrée » pour exécuter la suite du programme.Pour afficher sur l’écran un caractère, on utilisera les fonctions putchar(c) ou printf("%c", c).
1* : chaque appui sur les touches du clavier vient remplir le buffer de caractères
2* : la fonction scanf étant bloquante, l'appui sur retour charriot ('\n') vient lancer la routine de lecture du buffer de caractères qui est lu pour chaque scanf caractère par caractère.
En résumé :à la différence avec scanf %d ou %f (encodage des caractères pour générer la valeur entière ou réelle entrée) le scanf %c vient lire le caractère courant (son code ASCII) et le place dans la variable caractère (codée sur 8 bits).
Le scanf étant bloquant si l'on entre un caractère (suivi de retour charriot \n'), l'utilisation de scanf %c viendra lire le code ASCII du caractère suivi du code ASCII du retour charriot ('\n'), soit 2 caractères.
Quizz
3. Lecture ou affichage de caractères
Plusieurs solutions permettant de lire ou d'écrire des caractères :
Fonction de lecture caractère
Fonction d'affichage caractère
Prenons un premier exemple d'affichage de caractères de 3 façons :
sous forme décimale (%d)
sous forme hexadécimale (%x)
sous forme caractère (%c) c'est à dire le caractère associé à la table ASCII.
On peut voir que le caractère 'a' a le code ASCII0x61 ou 97 et que la touche retour charriot '\n' a le code ASCII 0xA ou 10.
Exemple
Résultat
char c = 'a';
printf("%d 0x%X %c\n", c, c, c);
c = 0x61;
printf("%d 0x%X %c\n", c, c, c);
c = '\n';
printf("%d 0x%X %c", c, c, c);
97 0x61 a
97 0x61 a
100xA
Quizz
4. Table ASCII
La table ASCII donnée ci-dessous donne le code de tous les caractères de 0 à 127 (0x7F). Cette table ASCII est découpée en plusieurs parties :
du code 0 au code 0x1F, on trouve les caractères de controle et notamment LF (Line Feed) qui en C correspond au code '\n' ou 0x0A, CR (Carriage Return) qui en C correspond au code '\r' ou 0x0D
du code 0x20 au code 0x2F, on trouve des caractères imprimables SP (SPace) qui en C a le code ' ' mais aussi '!' ou 0x21
du code 0x30 au code 0x39 , on trouve le code ASCII des chiffres '0' à '9'
du code 0x41 à 0x5A , on trouve les lettres majuscules de 'A' à 'Z'
du code 0x61 à 0x7A, on trouve les lettres minuscules de 'a' à 'z'
Voici quelques caractères non imprimables de 7 à 13 qui peuvent être utiles en C, citons par exemple '\a' pour générer un bip, r\r' pour revenir à la ligne (si l'on veut afficher du texte au même endroit (et écraser le texte précédent),'\t' pour déplacer le curseur d'une tabulation,...
Quizz
5. test sur les caractères
Nous avons vu que les chiffres, lettres majuscules et minuscules se suivent dans la table ASCII. Il sera donc possible d'effectuer des tests en utilisant les spécificités de la table ASCII.
Test
Ligne de code
Est un chiffre ?
(c >= '0' && c <= '9')
Est une lettre minuscule ?
(c >= 'a' && c <= 'z')
Est une lettre majuscule ?
(c >= 'A' && c <= 'Z')
Est une lettre ?
(c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
Est un caractère de controle ?
(c <=31 || c==127)
Modification
Langage C
Passer de lettre minuscule en majuscule
c = c + 'A' - 'a';
Passer de lettre majuscule en minuscule
c = c + 'a' - 'A';
2 exemples permettant de tester des voyelles (minuscules et/ou majsucules).
Exemple de programme de test de voyelles (lettres minuscules)
char c;
printf("entrer un caractere:");
c = getchar();
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' || c == 'y')
printf("voyelle et minuscule");
else
printf("autre");
Exemple de programme de test de voyelles (tout type de lettres minuscules ou majuscules)
char c;
printf("entrer un caractere:");
c = getchar();
if (c >= 'A' && c <= 'Z')//si lettre majuscule
c = c + 'a' - 'A';// passage en minuscule
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' || c == 'y')
printf("voyelle");
else
printf("autre");
Quizz
6. Lecture de plusieurs caractères
Dans l’exemple ci-dessous, si l’utilisateur a entré plusieurs caractères au clavier (« ABC »), le programme va lire tous les codes ASCII présents dans le buffer jusqu’au caractère '\n' qui est le caractère « Entrée » (fin de la saisie). Il va alors compter le nombre de caractères A entrés au clavier et afficher ce nombre de caractères.
Prenons un deuxième exemple qui veut lire 2 caractères et tester si ces 2 caractères sont identiques. N'oublions pas que pour débloquer les fonctions de lecture getchar ou scanf %c il faut que l'utilisateur tape sur Entrée. Le programme ci-dessous va vider le buffer de caractère while (getchar()!='\n'); aprés avoir lu le premier caractère, puis aprés avoir lu le deuxième caractère vider une nouvelle fois le buffer (pas nécessaire si le programme s'arrête ensuite).
#include<stdio.h>
int main()
{
char c1;
char c2;
printf("taper 1 caractere puis sur Entree:");
c1 = getchar();
while (getchar() != '\n'); //vider le buffer de caractere
printf("taper 1 caractere puis sur Entree:");
scanf("%c", &c2);
while (getchar() != '\n');//vider le buffer de caractere
if (c1 == c2)
printf("ok");
else
printf("ko");
return 0;
}
Terminons avec un dernier programme qui va lire tous les caractères entrés par l'utilisateur jusqu'au caractère de tabulation (qui a le code 9 et non 10 qui est le code du retour charriot). Il va alors analyser tous les caractères lu et afficher leur code en décimal, hexadécimal et le caractère associé.
Programme de test pour plusieurs caractères
Texte entré : abz95 &Z apres tab
int main() {
char c;
do {
c = getchar();
if (c >= '0' && c <= '9')
printf("un nombre : ");
elseif ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
printf("une lettre : ");
else
printf("autre chose : ");
printf("%c %d 0X%X\n", c, c, c);
} while (c != 9); //touche tab
}
une lettre : a 97 0X61
une lettre : b 98 0X62
une lettre : z 122 0X7A
un nombre : 9 57 0X39
un nombre : 5 53 0X35
autre chose :32 0X20
autre chose : & 38 0X26
une lettre : Z 90 0X5A
autre chose :9 0X9
Quizz
7. bibliothèque de fonctions ctype.h
La bibliothèque ctype.h propose des fonctions de test de caractères qui peuvent être utilisés à la place de tests utilisant les codes des caractères.
Tests
En langage C (fonctions de ctype.h)
Est un chiffre ?
intisdigit(intcharacter);
Est une lettre minuscule ?
intislower(intcharacter);
Est une lettre majuscule ?
intisupper(intcharacter);
Est une lettre ?
intisalpha(intcharacter);
Est un caractère de controle
intiscntrl(intcharacter);
Modifications
En langage C (fonctions de ctype.h)
Passer de lettre minuscule en majuscule
inttoupper(intcharacter);
Passer de lettre majuscule en minuscule
inttolower(intcharacter);
8. Récapitulatif
Il existe donc 3 solutions permettant de répondre à un problème associant des tests sur les caractères :
La première solution consiste à utiliser les spécificités du codage des caractères dans la fonction main
La deuxième solution consiste à écrire des fonctions permettant de tester les caractères
La troisième solution utilise les fonctions de la bibliothèque ctype.h