Chapitre suivantIndex des CoursChapitre précedentChapitre 8

LES CHAINES DE CARACTERES

 

Objectifs

   Connaître la convention de représentation des chaînes de caractères en C

•   Comprendre les entrées -sorties de chaînes

•   Manipuler les fonctions de traitement et  de conversion

Elément de contenu

•   La convention de représentation de chaînes de caractères en C

•   Les entrées sorties de chaînes

•   Les fonctions de concaténation de chaînes

•  Les fonctions de comparaison de chaînes

 Les fonctions de copie de chaînes

   Les fonctions de recherche dans une chaîne

•   Les fonctions de conversion

Certains langages (tels que le Basic ou le Turbo Pascal) disposent d’un véritable “type chaînes’’. Les variables d’un tel type sont destinées à recevoir des suites de caractères qui peuvent évoluer, à la fois en contenue et en longueur, au fil du déroulement du programme. Elles peuvent être manipulées d’une manière globale.

D’autres langages (tels que Fortran ou le Pascal standard) ne dispose pas d’un tel type chaîne. Pour traiter de telles informations, il est nécessaire de travailler sur des tableaux de caractères, dont la taille est nécessairement fixe (ce qui impose une longueur maximum aux chaînes et entraîne donc une perte de l ‘emplacement mémoire).

En langage C, il l’existe pas de véritable type chaîne, dans la mesure où on ne peut pas déclarer

des variables de ce type. Par contre, il existe une convention de représentation des chaînes.

Celle-ci est utilisée à la fois :

•     par te compilateur pour représenter les constantes chaînes (notées entre double quotes),

•     par un certain nombre de fonctions qui permettent de réaliser

-  les lectures ou écritures de chaînes,

-  les traitements classiques tels que la concaténation, recopie, comparaison, extraction

de sous-chaîne, conversions,….

Mais, comme il n’existe pas de type chaîne, il faudra prévoir un emplacement pour accueillir ces informations. Un tableau de caractères pourra faire l’affaire a c’est ce que nous allons utiliser dans ce chapitre. Mais nous verrons plus tard comment créer dynamiquement. des emplacements mémoires, lesquels seront alors repérés par des pointeurs.

1- LA CONVENTION DE REPRESENTATION DES CHAINES EN C

En C, une chaîne de caractères est représentée par une suite d’octets correspondant à chacun de ses caractères codés en ASCII, le tout étant terminé par un octet supplémentaire de code nul cela signifie que, d’une manière générale, une chaîne de n caractères occupe en mémoire un emplacement de n +1 octets.

1.1 Les constantes chaînes de caractères

C’est cette convention qu’utilise le compilateur pour représenter les constantes chaînes que vous introduisez dans vos programmes, sous des notations de la forme :

“bonjour“

De plus, une tel notation sera traduite par le compilateur on un pointeur sur des éléments de type char sur la zone mémoire correspondante.

Voici un programme illustrant ces deux particularités :

main()

{

char * adr ;

adr=“bonjour“ ;

do

printf(“%c“,*adr) ;

while(*adr++);

}

La déclaration :

char *adr

réserve un emplacement pour un pointeur sur un caractère (ou une suite de caractères)En ce qui concerne la constante :

‘‘bonjour’’

le compilateur a créé en mémoire la suite d’octets correspondants mais, dans l’affectation

adr- = “bonjour”

la notation bonjour a pour valeur, non pas la valeur de la chaîne elle même, mais son adresse ; on retrouve ici le même phénomène que pour les tableaux.

Voici un schéma illustrant la situation après l’exécution de cette affectation

b

o

n

j

o

u

r

\o

          adr

1.2 Initialisation de tableaux de caractères

Comme on l’a dit, nous sommes souvent amenés, en C, a placer des chaînes dans des tableaux de caractères.

Mais, si on déclare, par exemple :

char ch[20] ;

On ne pourra pas transférer une chaîne constante dans ch en écrivant une affectation du genre :

          ch = bonjour”;

En effet, ch est une constante pointeur et non une ivalue ; il n’est donc pas possible de lui attribuer une valeur.

Par contre, C nous autorise a initialiser notre tableau de caractères à l’aide dune chaîne constante. Ainsi, on pourra écrire :

char ch[20] =’’bonjour’’

Ceci sera parfaitement équivalent à une initialisation de ch réalisée par une énumération de caractères (sans oublier le code 0 noté \0) :

char ch[20]={‘b’,’o’ ,’n’,’j’,’o’,’u’,’r’,’\0’} ;

I.3 Initialisation de tableaux de pointeurs sur des chaînes

Nous avons vu qu’une constante chaîne de caractères était traduite par le compilateur en une adresse que l’on pouvait, par exemple, affecter à un pointeur sur une chaîne. Cela peut se généraliser à un tableau de pointeurs, comme dans :

char * jour [7] ={ “lundi”, “mardi”, “mercredi “, “jeudi”,

‘‘Vendredi’’, “ samedi’’, “ dimanche’’} ;

Cette déclaration réalise donc, à la fois

-  la création des 7 constantes chaînes correspondant aux 7 jours de la semaine,

-  l’initialisation du tableau jour avec les 7 adresses de ces 7 chaînes.

Voici un exemple utilisation cette déclaration :

main()

{

char *jour [7] = { “lundi “, “mardi “, “mercredi “, “jeudi

‘‘vendredi “, “samedi “, ‘‘dimanche ‘‘) ;

int i ;

printf(’’donnez un entier 1 et 7 :’’)

    scanf(”%d’’, &i) ;

printf (“le jour %d de la semaine est %s”, i, jour[i-1]) ;

}

      donnez un entier 1 et 7 :3 

le jour 3 de la semaine est mercredi

Il- LES ENTREES-SORTIE DE CHAINES

Le langage C offre plusieurs possibilités de lecture ou d’écriture de chaînes

•     l’utilisation du code format %s dans les fonctions printf et scanf ou (esscanf)

•     les fonctions spécifiques de lecture (gels) ou d’affichage (puts) d’une chaîne (une seule à la fois),

•     a fonction de lecture directe au clavier (cgets) qui présente l’avantage d’autoriser un contrôle de la taille de la chaîne lue et, partant, de vous protéger contre un éventuel risque de débordement.

Ici nous nous limitons aux entrées-sorties conversationnelles les autres possibilités seront examinées lors de l’étude des fichiers.

II.1 Les fonctions gets, puts et le code format %s

Examinons cet exemple de programme :

main()

{

char nom [ 20], prénom[2 0], ville[25] ;

printf(’’quelle est votre ville :’’) ;

gets(ville) ;

printf(’’donnez votre nom et votre prénom :’’) ;

scanf(‘’%s%s’’, nom ,prénom) ;

printf(‘’bonjour cher %s %s qui habite à ‘’,nom ,prénom) ;

puts(ville) ;

}

      Quelle est votre ville : Tunis

Donnez  votre nom et votre prénom : Foulen ben Foulen

Bonjour cher Foulen ben Foulen qui habite à Tunis

Les fonctions printfet sarnf permettent de lire et d’afficher simultanément plusieurs informations le type quelconque. Par contre gets et puts ne traitent qu’une chaîne à la fois.

De plus, les délimitations de la chaîne lue ne s’effectuent pas de la même façon avec scanf et gets. Plus précisément :

· avec le code %s de scanf les délimiteurs sont classiquement l’espace, la tabulation ou la fin de ligne. Ceci interdit la lecture d’une chaîne contenant des espaces.

· avec gets, seule la fin de ligne sert de délimiteur.

Dans tous les cas, on remarque que la lecture de n caractères implique le stockage on mémoire de n+1 caractères car le caractère de fin de chaîne (\0) est généré automatiquement par les fonctions de lecture.

Ainsi, dans notre précédent programme, il n’est pas souhaitable que le nom fourni en donnée contienne plus de 19 caractères.

Remarques :

1) Dans les appels des fonctions scanf et puts, les identificateurs de tableaux comme nom, prénom ou ville ne doivent pas être précédés de l’opérateur & puisqu’ils représentent déjà des adresse.

2) La fonction gets fournit en résultat, soit un pointeur sur la chaîne lue, soit un pointeur nul on cas d’anomalie.

3) La fonction puts réalise un changement de ligne en fin de l’affichage de la chaîne, ce qui n’est pas le cas de la fonction printf  avec le code format %s.

Les fonctions cgets et sscanf

Le problème de risque de débordement de l’espace alloué à une chaîne lue on donnée peut être résolue par l’utilisation de la fonction cgets à la place de gets. Celle-ci permet d’imposer un nombre maximum de caractères à lire.

Voici un exemple qui lit une chaîne comportant au maximum 27 caractères (28 avec le caractère nul de fin de chaîne).

# inc/ude <stdio h>

main()

{

char texte[30];

printf(‘’donnez un texte : ‘’) ;

texte [0]=28 ;

cgets(texte) ;

printf(‘’vous avez fini %d caractères \n ‘’,texte[1]) ;

puts(&texte[2]= ;

}

Donnez un texte :bonjour

Vous avez fini 7caractères

Bonjours

Donnez un texte abcdefghijklmnopqrstuvwxyza

Vous avez fourni 27 caractères abcdefghijklmnopqrstuvwxyza

En fait cgets utilise les deux premiers caractères de la “zone” dont on lui fournit l’adresse pour gérer sa lecture

·         le premier octet doit être initialisé par le programme au nombre maximum de caractères que l’on souhaite ranger en mémoire, y compris le caractère nul de fin

·         le second octet sera renseigné par cgets à la fin de l’opération pour indiquer le nombre de caractères effectivement lus.

Cette fonction ne lira pas plus de caractères que prévu. Si l’utilisateur cherche à en fournir davantage, il en sera informé par l’émission d’un bip sonore. Notez que, dans tous les cas, il doit valider sa réponse par la touche return.

Nous avons vu les problèmes posés par scanf on cas de réponse incorrecte de la part de l’utilisateur.

Il est possible de régler la plupart de ces problèmes on travaillant en deux temps

•     lecture d’une chaîne de caractères par cgets

•     vérification du format de manière comparable à ce que ferait scanf.

Voici un exemple de programme permettant de questionner l’utilisateur jusqu’à ce qu’il ait fournit une réponse satisfaisante :

# define LG 80

# def;ne LG3 LG+3

#include <stdio.h>

main()

{

int n, compte;

char c;

char tampon[LG3] ;

     tampon[0]=LG+1;
     do                

{

printf(“Donncz un entier et un caractère :’’) ;

cgcts tampon()                                       -

compte = sscanf(&tanpon[2],%d %c”, &n, &c,);

} while (compte <2) ;

printf <“merci pour, ‘‘%d %c “, n, c) ;

}

Donnez un enter et un caractère : bof

Donnez un entier et un caractère : a 125

Donnez un entier et un caractère : 12 bonjour

Merci pour 12 b

III- LES PONCTIONS DE CONCATENATION DE CHAINES

La concaténation est la juxtaposition de chaînes afin d’en former une seule. Elle est réalisée en C à l’aide de l ‘une des deux fonctions strcat et strncat (dont les prototypes figurent dans string. h)

111.1 La fonction strcat

Examinons cet exemple :

#include <string.h>

main()

{

char ch l[50]=’’bonjour’’ ;                                                      avant bonjour
char *0h2=’’monsieur”;                                                          après : bonjour monsieur:
printf (“avant: %s\n “, ch1);
strcat(ch 1, ch2);
printf (“après: %s\n’’,ch 1);

}

Il faut noter la différence entre les deux déclarations (avec initialisation) de chacune des deux chaînes ch1 et ch 2. La première permet de réserver un emplacement plus grand que la constante chaîne qu’y trouve place initialement.

L’appel de strcat se présente ainsi :

strat (destination, source)

Cette fonction recopie [a seconde chaîne source à la suite de a première destination, après en avoir effacé le caractère de fin.

Remarque :

1)   Aucun contrôle de longueur n’est réalisé par cette fonction ;il  est nécessaire que emplacement réservé pour la première chaîne soit suffisant  pour y recevoir la partie à lui concaténer.

2) Après exécution de srtcat, la première chaîne n’existe p\us en tant que telle.

3) strcat fournit un résultat

-   l’adresse de la chaîne correspondant à la concaténation des deux chaînes fournies en argument, lorsque l’opération s’est bien déroulée. Ce n’est rien d’autre que l’adresse de ch1.

Le pointeur nul lorsque l’opération s’est mal déroulée.

II.2 La fonction strncat

Cette fonction, dont l’appel se présente ainsi :

strcat (destination, source, igmax)

Travail le de façon semblable a strcat en offrant on outre un contrôle sur le nombre de caractères qui seront concaténés à la chaîne d’arrivée (destination).

#include <string. h>

main()

{

char ch[50] = “bonjour’’ ;                                                     avant :bonjour

char *ch2 = “ monsieur’;                                                       après :bonjour monsieur

printf(’’avant %s\n’’;ch1);

strncat (ch1,ch2,6);;

printf(’’apres:%s\n’’;ch1);

}

Il   faut noter que le contrôle ne porte pas sur la longueur de la chaîne finale. Fréquemment on déterminera ce nombre maximal de caractères à recopier comme étant la différence entre la taille totale de la zone réceptrice et la longueur courante de la chaîne qui s’y trouve. Cette dernière s’obtiendra par la fonction strlen. Par exemple :

strlen(ch1)

Fournit une valeur de type int correspondant à la longueur de la chaîne ch1. Le caractère nul de fin, n’étant pas comptabilisé.

IV- LES FONCTIONS DE COMPARAISON DE CHAINES

Il   est possible de comparer deux chaînes en utilisant l’ordre des caractères défini par le code

ASCII.

a)  La fonction :

            strcmp (ch1, ch2)                                            (string. h)

compare deux chaînes dont on lui fournit les adresses et elle fournit une valeur entière définie comme étant :

·         positive si ch1 > ch2 (c’est à dire chl vient après ch2 au sens de l’ordre défini par le code ASCII)

·         nulle si ch1 = ch2 (c’est à dire que chl et ch2 contiennent exactement la même suite de caractères).

·         négative si ch 1 < ch2

Par exemple :

strcmp(”bonjour “, “monsieur’’)

est négatif et

strcmp(”Tunis2 “, ‘Tunis10’’)

est positif.

b)  La fonction

            strncmp (ch,ch2,lgmax)                                  (string.h)

Travaille comme strcmop mais elle limite la comparaison au nombre maximum de caractères indiqué par l’enlier lgmax.

Par exemple :

strncmp(’’bonjour “, ‘‘bon’’, 4)

est positif tandis que

strcmp(’’bonjour “, ’’bon “, 2)

vaut zéro.

c) Enfin, les deux fonctions

             stricmp (ch1, ch2)                                           (string.h)
             strnicmp (ch1, ch2, lgmax)                             (string.h)

Travaillent respectivement comme strcmp et strncmp, mais sans tenir compte de la différence entre majuscules et minuscules (pour les seuls caractères alphabétiques).

V-  LES FONCTIONS DE COPIE DE CHAINES 

a) La fonction :

            strcpy (destin, source)                                     (string.h)

Recopie la chaîne située à l’adresse source dans l’emplacement d’adresse destin. Là aussi, il faut que la taille du second emplacement soit suffisante pour accueillir la chaîne  à recopier.

b) La fonction :

            strncpy (destin, source, lgmax,)                       (string.h)

Procède de manière analogue à strcpy, en faisant la recopie au nombre de caractères précisés par l’expression entière lgmax.

Il faut noter que si la longueur de la chaîne source est inférieure à cette longueur maximale son caractère de fin sera effectivement recopié. Mais dans le cas contraire, il ne le sera pas. L’exemple suivant illustre les deux situations :

#include <string. h>

main()

{

     char ch1 [20] = “xxxxxxxxxxxxxxxxx”;                             donnez un mot: bon
     char ch2[20];                                                                     bon
     printf(’’donnez un mot:’’
);
     gets(ch2) ;                                                                          donnez un mot: bonjour
     strncpy(ch1, ch2, 6);                                                          bonjourxxxxxxxxxxxx

printf(”%s”, ch1);

}

c)  Enfin, la fonction : 

             strcpy(chaîne)                                                 (string.h)

Effectue une recopie de la chaîne dont on lui fournit l’adresse dans un emplacement qu’elle alloue dynamiquement et dont elle fournit l’adresse on résultat (elle fournit le pointeur nul si elle n’a pas pu disposer de suffisamment  de place mémoire.)

VI- LES FONCTIONS DE RECHERCHE DANS UNE CHAINE

On trouve, on langage C, des fonctions de  recherche de “l’occurrence’’ dans une chaîne d’un caractère ou d’une autre chaîne (nommée alors sous-chaîne).

Ces fonctions fournissent comme résultat l’adresse de l’information cherchée on cas de succès et le pointeur nul dans le cas contraire.

             strchr (chaîne, caractère)                               (string.h)

Recherche, dans chaîne la première position où apparaît le caractère mentionné

             strchr (chaîne, caractère)                               (string.h)

Réalise le même traitement que strchr, mais en explorant la chaîne mentionné à partir de la fin.

Elle fournit donc la dernière occurrence du caractère mentionné.

             strstr (chaîne, sous-chaîne)                             (string.h)

Recherche dans chaîne la première occurrence complète de la sous-chaîne mentionnée.

             strpbrk (chaîne 1, chaine2)                             (string. h)

Recherche, dans chaîne1 la première occurrence d’un caractère quelconque de chaine2.

Voici un programme illustrant le fonctionnement de ces  quatre fonctions :

#înc/ude <string.h>

#define c ’e’

#define s ch  ‘re’

#define voy  ‘aeiou’

main()

{

char ,mot[40];

char *adr ;

printf(’’donnez un mots:);

gets (mot);

if (adr=strchr(mot,c))

printf(’’première occurrence de%c en %s\n’’,c,adr);

if (adr=strrchr(mot,c))

printf(’’dernière occurrence de %c en %s\n’’,c, adr) ;

if (adr = strstr(mot,sch))

printf (“première occurence de %s en %s\n’’;sch,adr) ;

if (adr =strpbrk(mot,voy))

printf (“première occurrence de l’une des lettres de %s en %s\n’’,voy,adr) ;

}

Donnez un mot : correspondance

Première  occurrence de e en espondances

Dernière occurrence de e en es

Première occurrence de re en repondances

Première occurrence de l’une des lettres de aeiou en orréspondance

Donnez un  mot : bonjour

Première occurrence de l’une des lettres de aeiou en onjour

VII- LES FONCTIONS DE CONVERSION

VII.1  Conversion d’une chaîne on une valeur numérique

Il existe trois fonctions permettant de convertir une chaîne de caractères en une valeur numérique de type int, long ou double. Ces fonctions ignorent les éventuels espaces de début de chaîne et utilisent les caractères suivant pour fabriquer une valeur numérique. Le premier caractère invalide arrête l’exploration. Par contre, si aucun caractère n’est exploitable, ces fonctions fournissent un résultat nul.

            atoi (chaine)                                        (stdlib.h)

fournit un résultat de type int;

             atol(chaine)                                         (stdlib.h)

fournit un résultat de type long;

            atof(chaine)                                         (stdlib.h)

fournit un résultat de type double;

Voici un programme illustrant les possibilités de atoi et atof:

#include <stdlib. h>

main()

{

char ch[40] ;

int n ;

do

{

printf(’’donnez une chaîne :’’) ;

gets(ch);

printf(‘’----->int         :%d\n’’,n=atoi(ch));

printf(“----->double  :%e\n” ,atof(ch));

} while(n);

}

donnez une chaîne :123

----->int          :123

----->double    :1.230000e+02

donnez une chaine :-123.45

----->int          :-123

----->double    :-1.234500e+02

donnez une chaîne : 123.45e6

----->int          :123

----->double    :1.234500e+08

donnez une chaîne :0

----->int          :0

----->double    :0.000000e+00

VII.2 Conversion d’une valeur numérique en une chaîne

Nous nous limiterons ici au fonctions de conversion d’un entier en une chaîne (il existe des fonction permettant de convenir un nombre flottant on une chaîne). Celles-ci permettent d’exprimer un nombre non seulement sous forme d’une suite de chiffres en base 10, mais également dans n’importe quelle base comprise entre 2 et 36. Elles sont particulièrement bien adaptées pour afficher par exemple un nombre en binaire.

Ces trois fonctions fournissent en résultat un pointeur sur la chaîne obtenue

            itoa ( entier,chaine,base )                                  (stdlib.h)

travaille avec un entier de type int.

            itoa ( entier,chaine,base )                               (stdlib.h)

travaille avec un entier de type long.

            ultoa  (entier,chaine,base )                             (stdlib.h)

travaille avec un entier de type unsigned long.

Voici un exemple d’utilisation de la fonction itoa :

#include <stdlib. h>

main()

{                                                              

char ch[40];

int n,b;

do

{

printf(‘’donner un nombre et une base : &b);

printf(”  %s\n”, itoa(n, ch, b));

}while(n) ;

}

donner un nombre et une base123

donner un nombre et une base :-12310

-123

donner un nombre et une base :8711

7a

donner un nombre et une base :20016

c8 une base :-20016

ff38

donner un nombre et une base :3536

z

donner un nombre et une base :2002

11001000

donner un nombre et une base :-12

1111111111111111

donner un nombre et une base :00

Chapitre précedentIndex des CoursChapitre suivant

Révisé le :23-Sep-2007| ©2007 www.technologuepro.com