Chaines de caractères
"Strings"
Accueil

du site

Définitions d'une chaîne de caractères
Une chaîne de caractères peut s'enregistrer en mémoire comme un tableau de type char.

Exemple :

Eléments utilisés dans ce programme : Tableaux.- Boucle "for" :
Postincrémentation dans l'expression :" i++"
putchar(caractere) est une procédure de la librairie "stdio"
permettant d'afficher "caractere" à l'écran.

#include <stdio.h>

int main()
{
--char Mot[7]={'B','o','n','j','o','u','r'};
--int i;
--for(i=0; i<7; i++) putchar(Mot[i]);
--return 0;
}

Ce n'est pas très pratique à écrire car il faut compter les caractères.

Certains compilateurs acceptent :
char Chaine[]={'B','o','n','j','o','u','r'];
La réservation des 7 caractères est automatiquement effectuée, mais on ne connaît pas ce nombre et il peut y avoir des difficultés de repérer la fin de la chaîne.

Ce problème de nombre de caractères a été résolu de plusieurs manières dans les divers langages:

  • dans le langage Pascal, une chaîne de caractères est définie par le pointeur du tableau et un entier donnant le nombre de caractères de la chaîne.
  • en langage C on a préféré ajouter au tableau un dernier caractère égal à zéro (terminateur nul.
    Attention ! il ne s'agit pas du "caractère zéro ' 0 '. Mais de l'entier zéro 0.
    char Chaine[]={'B','o','n','j','o','u','r',0];

Cette dernière forme présente de très nombreux avantages comme nous allons le voir dans les exemples qui vont suivre.

A partir de maintenant, chaque fois que l'on prononcera le mot "chaîne de caractères" ou "chaîne" tout court, "string" en anglais, on renverra à cette dernièrere définition.

Chaînes littérales ("Chaine littérale")


Le langage C permet de définir facilement des chaînes de caractères courtes explicitées littéralement.
Nous reprenons ici un court programme que nous avons déjà rencontré :

//PremProg.c

#include <stdio.h>

int main()
{
;printf("Bonjour !"); //Fonction d'affichage
;return 0;
}

"Bonjour !" est une chaîne au sens de C.
Le compilateur a bien réservé 9 caractères plus le terminateur 0 en mémoire.
Vous vous demandez quel peut être l'identificateur générique d'un tel tableau ?
Eh bien ... c'est "Bonjour !" lui-même.

La preuve ce programme :

#include <stdio.h>

int main()
{
;char *p;
;p = "Bonjour !";
;
printf(p);
;putchar(p[3]); //Affiche 'j'
;
return 0;
}


Nous rappelons que "putchar('x')"
est une procédure de la librairie "stdio"
permettant d'afficher le caractère x
à l'écran

Interprétons :

Nous avons déclaré un pointeur de caractères et nous lui avons affecté la valeur "Bonjour !"
Si "Bonjour !" n'était pas de type pointeur de caractère, le compilateur nous aurait signalé une erreur.
Ce qu'il n'a pas fait.

Par ailleurs, printf(p); affiche bien "Boujour !" à l'écran, ce qui prouve que p est bien le pointeur sur la chaîne de caractères "Bonjour !".

Enfin, s'il fallait une autre preuve : p[3] est bien affiché comme la lettre 'j'

ATTENTION !
Une chaîne ainsi définie est constante ! Vous ne pouvez pas modifier ses caractères.

#include <stdio.h>

int main()
{
;char *p;
;p = "Bonjour !";
;p[2]='x'; Erreur fatale à l'exécution !
;
printf(p);
;
return 0;
}

 


Affichage d'une chaîne à l'écran

 

#include <stdio.h>

int main()
{
;char Chaine[8]={'B','o','n','j','o','u','r',0};
;//Certains compilateurs acceptent cet équivalent :
;//char Chaine[]={"Bonjour"};

;//Le terminateur 0 est en place en fin de chaîne
;int i = 0;
;while(Chaine[i])
;{
; putchar(Chaine[i]);
; i++;
;}

;return 0
}


Eléments utilisés dans ce programme : Tableaux - Algorithme while( ) {...;} - Variables booléennes

Explications :

;while(Chaine[i])
;{
; putchar(Chaine[i]);
; i++;
;}

Tant que Chaine[i] n'est pas nul, l'algorithme affichele caractère Chaine[i] et
incrémente "i" tout de suite après à chaque tour.
Si Chaine[i] est nul, nous sommes arrivés en fin de chaîne.
Dans ce cas, la condition booléenne dans les parenthèses du while( Chaine[i] )
est zéro, équivalente à false : on n'affiche donc pas le terminateur nul et on sort de l'algorithme.



Conversion d'une chaîne en minuscules ou en majuscules

#include <stdio.h>

int main()
{
;char Chaine[8]={'B','o','n','j','o','u','r',0};
;//Certains compilateurs acceptent cet équivalent :
;//char Chaine[]={"Bonjour"};
;
;int i = 0;
;while(Chaine[i])
;{
;;Chaine[i] = Chaine[i] | 0x20;
; putchar(Chaine[i]);
; i++;
;}

;return 0
}

Ce programme convertit toute la chaîne en minuscules. Explications :
Il suffit de regarder le tableau des valeurs numériques des caractres ASCII
pour y voir que les majuscules et les minuscules ne diffèrent que par le bit 5 :
avec les bits numérotés comme ceci: 7654321.
Ce bit est nul pour les majuscules et égal à un pour les minuscules.

On peut donc obtenir une minuscule en masquant une majuscule par l'octet 00100000 en binaire
ce qui correspond à la valeur "20" en hexadécimal, qui s'écrit 0x20 en langage C.

Donc :
minuscule = majuscule ! 0x20;
Nous rappelons ici que l'opérateur " | " est l' opérateur "OU" bit à bit du langage C.

Allons plus loin, 0x20 est le code ASCII de l'espace qui s'écrit : ' ' (soit deux apostrophes séparées par un espace).
Donc :
minuscule = majuscule |' ';

Enfin, si "lettre" désigne un identificateur de caractère, elle sera systématiquement transformée en minuscule par l'opération :
lettre = lettre |' ';
Ou, mieux encore par (voir opérateurs d'affectation):

lettre|=' ';

On vous laisse le soin de montrer que la transformation en majuscule se fait par :

lettre&=~' ';

Nous rappelons que le "tilde" ~ est l'opérateur de complémentation bit à bit du langage C,
et que le '&' en est l'opérateur ET bit à bit .

#include <stdio.h>

int main()
{
;char Chaine[8]={'B','o','n','j','o','u','r',0};
;//Certains compilateurs acceptent cet équivalent :
;//char Chaine[]={"Bonjour"};
;
;int i = 0;
;while(Chaine[i])
;{
;;Chaine[i]|=' ';
; putchar(Chaine[i]); //Tout en minuscules
; i++;
;}
;putchar('\n'); //A la ligne

;i=0;
;
while(Chaine[i])
; putchar(Chaine[i++]&=~' '); //Tout en majuscules

;putchar('\n');

;return 0
}

Observez comment on est arrivé à réduire le code en insérant les opérations :

  • D'abord :
    Chaine[i]&=~' ';
    putchar(Chaine[i]);
    peut se réduire à :
    putchar(Chaine[i]&=~' ');
  • Ensuite : la postincémentation de i peut s'insérer dans :
    putchar(Chaine[i++]&=~' ');

Autres procédures de conversion Min Maj

Rappelons que l'on se base sur les codes ASCII pour l'ordre alphabétique des caractères.
Mais les lettres minuscules ont des codes ASCII supérieurs à toutes les majuscules.
Ainsi "Xavier" est avant "andré" par ordre alphabétique !

Par ailleurs 'é' et 'e' n'ont pas le même code et pourtant ils ont la même place par ordre alphabétique.

Le problème des minuscule et des lettres accentuées peut êtret réglé comme suit :

//===============================
char MinMaj(char c)
{
 if((c >='a') && (c <='z'))
   c-=' '; //L'espace ' ' a pour code 0010 0000 = 20 hex.
 else
  switch (c)
  {
   case 'à' :
   case 'â' :
   case 'ä' : c ='A' ;break;

   case 'ç' : c ='C' ;break;

   case 'é' :
   case 'è' :
   case 'ê' :
   case 'ë' : c ='E' ;break;

   case 'î' :
   case 'ï' : c ='I' ;break;

   case 'ô' :
   case 'ö' : c = 'O' ;break;

   case 'ù' :
   case 'û' :
   case 'ü' : c = ='U' ;break;
   default : break;
  }
 return c;
}
//===============================


Dès lors, la conversion d'une chaîne en majuscules estr très simple, n'est-ce-pas ?

void ConvertToMaj(char * pChaine)
{
 while(*pChaine = MinMaj(*pChaine)) pChaine ++;
}

 


Comparaisons de chaînes

La procédure suivante compare deux chaînes de caractères.

Dans un premier temps nous ignorons le problème des minuscules et des accents,nous le traiteronsplus loin.

bool Chaine1AvantChaine2(char * Ch1, char * Ch2)
{

 int i = 0;
 while((Ch1[i] == Ch2[i]) && Ch1[i]) i++;


  if(Ch1[i] < Ch2[i]) return true;
  else return false;
}

  
Variante dans le langage des pointeurs:

bool Chaine1AvantChaine2(char * Ch1, char * Ch2)
{

 
while((*Ch1 == *Ch2) && *Ch1){Ch1++;Ch2++;};

 if(*Ch1<*Ch2) return true;
 return false;
}

  •   Souvenez-vous que le terminateur d'une chaîne est zéro et que : (*Ch1 == 0) équivaut à (*Ch1 == false)
  •   Dans le langage des tableaux (arrays) : Ch1[i] == 0 équivant à Ch1[i] == false


Dans un second temps nous abordons le problème des minuscules et des accents signalé plus haut.
Cependany, il faut savoir ce que l'on veut lorsqu'on décide de mettre en place une comparaison qui ne distinguera pas le 'e' du 'E' du 'ê' ou du 'è' etc....

bool Chaine1AvantChaine2(char * Ch1, char * Ch2)
{

 
while((MinMaj(*Ch1) == MinMaj(*Ch2)) && *Ch1){Ch1++;Ch2++;};

 if(MinMja(*Ch1)<MinMaj(*Ch2)) return true;
 return false;
}

//Bien tentendu, la procédure MinMaj() utilisée est celle écrite plus haut

 


Sommaire Langage C
Accueil

du site