Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
CHAPITRE VIII
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
En langage C, il n’existe pas de véritable type chaîne
En revanche, il existe une convention de représentation des chaînes.
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
Une chaine constante est traduite par le compilateur en un pointeur (sur des éléments de type char) sur la zone mémoire correspondante.
1) Représentation des chaînes
#include <stdio.h>
main()
{ char * adr ;
adr = "bonjour" ;
while (*adr)
{ printf ("%c", *adr) ;
adr++ ;
}
}
réserve simplement l’emplacement pour un pointeur sur un caractère (ou une suite de caractères)
"bonjour" le compilateur a créé en mémoire la suite d’octets correspondants
Et affecte l’adresse de "bonjour" à adr
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
La flèche en trait plein correspond à la situation après l’exécution de l’affectation : adr = "bonjour" ;
Les autres flèches correspondent à l’évolution de la valeur de adr, au cours de la boucle.
1) Représentation des chaînes
b
o
n
j
o
u
r
\0
adr
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
En effet, ch est une constante pointeur qui correspond à l’adresse que le compilateur a attribuée au tableau ch ; ce n’est pas une lvalue ;
Impossible de lui attribuer une autre valeur (ici, il s’agirait de l’adresse attribuée par le compilateur à la constante chaîne "bonjour").
En revanche, C vous autorise à initialiser votre tableau de caractères à l’aide d’une chaîne constante.
C’est parfaitement équivalent à une initialisation de ch réalisée par une énumération de caractères (en n’omettant pas le code zéro – noté \0) :
1) Représentation des chaînes
char ch[20] ;
ch = "bonjour" ;
char ch[20] = "bonjour"
char ch[20] = { 'b','o','n','j','o','u','r','\0' }
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
De plus, comme le langage C autorise l’omission de la dimension d’un tableau lors de sa déclaration, lorsqu’elle est accompagnée d’une initialisation, il est possible d’écrire:
Celle-ci réserve un tableau, nommé message, de 8 caractères (compte tenu du 0 de fin).
1) Représentation des chaînes
char message[] = "bonjour" ;
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
Nous avons vu qu’une chaîne constante était traduite par le compilateur en une adresse que l’on pouvait, affecter à un pointeur sur une chaîne.
Cela peut se généraliser à un tableau de pointeurs, comme dans :
Cette déclaration réalise donc à la fois la création des 7 chaînes constantes correspondant aux 7 jours de la semaine et l’initialisation du tableau jour avec les 7 adresses de ces 7 chaînes.
1) Représentation des chaînes
char * jour[7] = { "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi", "dimanche" } ;
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
Exemple :
1) Représentation des chaînes
main()
{
char * jour[7] = { "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi", "dimanche" } ;
int i ;
printf ("donnez un entier entre 1 et 7 : ") ;
scanf ("%d", &i) ;
printf ("le jour numéro %d de la semaine est %s", i, jour[i-1] ) ;
}
donnez un entier entre 1 et 7 : 3
le jour numéro 3 de la semaine est mercredi
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
Nous avons un tableau de sept pointeurs, chacun d’entre eux désignant une chaîne constante
1) Représentation des chaînes
b
o
n
j
o
u
r
\0
message
l
u
n
d
i
\0
m
a
r
d
i
\0
m
e
r
c
r
e
d
i
\0
jour
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
Le C offre plusieurs possibilités de lecture ou d’écriture de chaînes :
Exemple:
2) Pour lire et écrire des chaînes
#include <stdio.h>
main()
{
char nom[20], prenom[20], ville[25] ;
printf ("quelle est votre ville : ") ;
gets (ville) ;
printf ("donnez votre nom et votre prénom : ") ;
scanf ("%s %s", nom, prenom) ;
printf ("bonjour cher %s %s qui habitez à ", prenom, nom) ;
puts (ville) ;
}
quelle est votre ville : Paris
donnez votre nom et votre prénom : Dupont Yves
bonjour cher Yves Dupont qui habitez à Paris
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
Les fonctions printf et scanf permettent de lire ou d’afficher simultanément plusieurs informations de type quelconque.
En revanche, gets et puts ne traitent qu’une chaîne à la fois.
la délimitation de la chaîne lue ne s’effectue pas de la même façon avec scanf et gets.
Dans tous les cas, la lecture de n caractères implique le stockage en mémoire de n+1 caractères, car le caractère de fin de chaîne (\0) est généré automatiquement par toutes les fonctions de lecture (notez toutefois que le caractère séparateur – fin de ligne ou autre – n’est pas recopié en mémoire).
2) Pour lire et écrire des chaînes
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
Dans les appels des fonctions scanf et gets, les identificateurs de tableau comme nom, prenom ou ville n’ont pas besoin d’être précédés de l’opérateur & puisqu’ils représentent déjà des adresses. La norme prévoit toutefois que si l’on applique l’opérateur & à un nom de tableau, on obtient l’adresse du tableau. Autrement dit, &nom est équivalent à nom
Étant donné que gets consomme la fin de ligne servant de délimiteur, alors que le code %s de scanf ne le fait pas, il n’est pas possible, dans le programme précédent, d’inverser les utilisations de scanf et de gets (en lisant la ville par scanf puis le nom et le prénom par gets) : dans ce cas, la fin de ligne non consommée par scanf amènerait gets à introduire une chaîne vide comme nom.
D’une manière générale, d’ailleurs, il est préférable, autant que possible, de faire appel à gets plutôt qu’au code %s pour lire des chaînes.
2) Pour lire et écrire des chaînes
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
Nous avons vu, les problèmes posés par scanf en cas de réponse incorrecte de la part de l’utilisateur. Il est possible de régler la plupart de ces problèmes en travaillant en deux temps :
effectue sur l’emplacement dont on lui fournit l’adresse (premier argument de type char *) le même travail que scanf effectue sur son tampon.
3) Pour fiabiliser la lecture au clavier :le couple gets & sscanf
sscanf (adresse, format, liste_variables)
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
Voici un exemple d’instructions permettant de questionner l’utilisateur jusqu’à ce qu’il ait fourni une réponse satisfaisante
3) Pour fiabiliser la lecture au clavier : le couple gets & sscanf
#include <stdio.h>
#define LG 80
main()
{
int n, compte ;
char c ;
char ligne [LG+1] ;
do
{
printf ("donnez un entier et un caractère : ") ;
gets (ligne) ;
compte = sscanf (ligne, "%d %c", &n, &c) ;
}
while (compte < 2 ) ;
printf ("merci pour %d %c\n", n, c) ;
}
donnez un entier 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
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
Rappelons qu’il n’y a pas de véritable type chaîne en C, mais simplement une convention de représentation.
On ne peut jamais transmettre la valeur d’une chaîne, mais seulement son adresse, ou plus précisément un pointeur sur son premier caractère.
Ainsi, pour comparer deux chaînes, on transmettra à la fonction concernée (strcmp) deux pointeurs de type char *.
Pour recopier une chaîne d’un emplacement à un autre, on fournira à la fonction voulue (strcpy) l’adresse de la chaîne à copier et l’adresse de l’emplacement de destination.
Il faudra voir si vous disposer de suffisamment de place à cet endroit
4) Généralités sur les fonctions portant sur des chaînes
char string2[20]="red dwarf";
char string1[20]="";
strcpy(string1, string2);
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
La fonction strlen fournit en résultat la longueur d’une chaîne dont on lui a transmis l’adresse en argument. Cette longueur correspond tout naturellement au nombre de caractères trouvés depuis l’adresse indiquée jusqu’au premier caractère de code nul, ce caractère n’étant pas pris en compte dans la longueur.
4) Généralités sur les fonctions portant sur des chaînes
strlen ("bonjour");
char * adr = "salut" ;
strlen (adr);
vaudra 7
vaudra 5
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
Exemple
5) Les fonctions de concaténation de chaînes
#include <stdio.h>
#include <string.h>
main()
{
char ch1[50] = "bonjour" ;
char * ch2 = " monsieur" ;
printf ("avant : %s\n", ch1) ;
strcat (ch1, ch2) ;
printf ("après : %s", ch1) ;
}
avant : bonjour
après : bonjour monsieur
Notez la différence entre les deux déclarations (avec initialisation) de chacune des deux chaînes ch1 et ch2.
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
Offre en un contrôle sur le nombre de caractères qui seront concaténés à la chaîne d’arrivée.
5) Les fonctions de concaténation de chaînes
avant : bonjour
après : bonjour monsi
#include <stdio.h>
#include <string.h>
main()
{
char ch1[50] = "bonjour" ;
char * ch2 = " monsieur" ;
printf ("avant : %s\n", ch1) ;
strncat (ch1, ch2, 6) ;
printf ("après : %s", ch1) ;
}
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
compare deux chaînes dont on lui fournit l’adresse et elle fournit une valeur entière définie comme étant :
Exemple
6) Les fonctions de comparaison de chaînes
strcmp ( chaîne1, chaîne2 )
strcmp ("bonjour", "monsieur");
strcmp ("paris2", "paris10");
négatif
positif
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
travaille comme strcmp mais elle limite la comparaison au nombre maximal de caractères indiqués par l’entier lgmax.
Exemple
6) Les fonctions de comparaison de chaînes
strncmp ( chaîne1, chaîne2, lgmax )
strncmp ("bonjour", "bon", 4);
strncmp ("bonjour", "bon", 2);
positif
zéro
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
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).
6) Les fonctions de comparaison de chaînes
stricmp ( chaîne1, chaîne2 )
strnicmp ( chaîne1, chaîne2, lgmax )
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
Recopie la chaîne située à l’adresse source dans l’emplacement d’adresse but.
Il est nécessaire que la taille du second emplacement soit suffisante pour accueillir la chaîne à recopier, sous peine d’écrasement intempestif.
Cette fonction fournit comme résultat l’adresse de la chaîne but.
Procède de manière analogue à strcpy, en limitant la recopie au nombre de caractères précisés par l’expression entière lgmax.
Si la longueur de la chaîne source est inférieure à cette longueur maximale, son caractère de fin (\0) sera effectivement recopié. Mais, dans le cas contraire, il ne le sera pas. L’exemple suivant illustre les deux situations
7) Les fonctions de copie de chaînes
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
7) Les fonctions de copie de chaînes
#include <stdio.h>
#include <string.h>
main()
{
char ch1[20] = "xxxxxxxxxxxxxxxxxxx" ;
char ch2[20] ;
printf ("donnez un mot : ") ;
gets (ch2) ;
strncpy (ch1, ch2, 6) ;
printf ("%s", ch1) ;
}
donnez un mot : bon
bon
_______
donnez un mot : bonjour
bonjouxxxxxxxxxxxxx
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
Plusieurs fonctions de recherche de l’occurrence dans une chaîne d’un caractère ou d’une autre chaîne (sous-chaîne).
Elles fournissent comme résultat un pointeur de type char * sur l’information cherchée en cas de succès, et le pointeur nul dans le cas contraire.
Voici les principales.
Recherche, dans chaîne, la première position où apparaît le caractère.
Même chose que strchr, mais en explorant la chaîne concernée à partir de la fin. Elle fournit donc la dernière occurrence du caractère.
recherche, dans chaîne, la première occurrence complète de la sous-chaîne.
8) Les fonctions de recherche dans une chaîne
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
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, à l’image de ce que font les codes de format %d, %ld et %f, utilisent les caractères suivants pour fabriquer une valeur numérique. Le premier caractère invalide arrête l’exploration. En revanche, ici, si aucun caractère n’est exploitable, ces fonctions fournissent un résultat nul.
fournit un résultat de type int.
fournit un résultat de type long.
fournit un résultat de type double.
9) Les fonctions de conversion
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
La norme ne prévoit pas de fonctions de conversion d’une valeur numérique en chaîne.
En revanche, elle prévoit une fonction sprintf, symétrique de sscanf.
Elle permet de convertir en chaîne une succession de valeurs numériques, en y incorporant, le cas échéant, d’autres caractères.
Exemple, si n, de type int, contient 15 et si p, de type float, contient 785.35 et si tab est un tableau de caractères de taille suffisante, l’instruction suivante :
placera dans tab, la chaîne suivante (elle sera bien terminée par un caractère \0) :
9) Les fonctions de conversion
sprintf (tab, "%d articles coutent %8.2f F", n, p) ;
15 articles coutent 785.35 F
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
On sait qu’une convention de représentation de la fin d’une chaîne existe ; en revanche, rien n’est prévu pour son début.
En fait, toute adresse de type char * peut toujours faire office d’adresse de début de chaîne.
Exemple
dans l’exemple de programme strcat
10) Quelques précautions à prendre avec les chaînes
char * adr = "bonjour" ;
strlen (adr + 2);
serait acceptée : elle aurait pour valeur 5 (longueur de la chaîne commençant en adr+2).
strcat (ch1, ch2) ;
strcat (ch1, ch2 + 4) ;
Le programme afficherait alors simplement :
bonjoursieur
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
A priori, la norme interdit la modification de quelque chose de constant.
Peut ne pas être accepter par le compilateur
10) Quelques précautions à prendre avec les chaînes
strcat (ch1 + 2, ch2) ;
on obtiendra le même résultat qu’avec le programme initial (bonjour monsieur) puisque ch2 sera toujours concaténée à partir du même 0 de fin !
strcat (ch1 + 10, ch2) ;
on viendrait écraser un emplacement situé en dehors de la chaîne d’adresse ch1.
char * adr = "bonjour" ;
*adr = 'x' ; /* bonjour va-t-il se transformer en xonjour ? */
* (adr + 2) = 'x' ; /* bonjour va-t-il se transformer en boxjour ? */
Exercice 01:
Lesquelles des chaînes suivantes sont initialisées correctement? Corrigez les déclarations fausses et indiquez pour chaque chaîne de caractères le nombre d'octets qui sera réservé en mémoire.
a) char a[] = "un\ndeux\ntrois\n";
b) char b[12] = "un deux trois";
c) char c[] = 'abcdefg';
d) char d[10] = 'x';
e) char e[5] = "cinq";
f) char f[] = "Cette " "phrase" "est coupée";
g) char g[2] = {'a', '\0'};
h) char h[4] = {'a', 'b', 'c'};
i) char i[4] = "'o'";
Exercice 1 :
Quels résultats fournira ce programme :
#include <stdio.h>
main()
{
char * ad1 ;
ad1 = "bonjour" ;
printf("%s\n", ad1) ;
ad1 = "monsieur" ;
printf("%s\n", ad1) ;
}
Exercice 2 :
Quels résultats fournira ce programme :
#include <stdio.h>
main()
{
char * adr = "bonjour" ; /* 1 */
int i ;
for (i=0 ; i<3 ; i++) putchar(adr[i]) ; /* 2 */
printf ("\n") ;
i = 0 ;
while (adr[i]) putchar(adr[i++]) ; /* 3 */
}
Exercice 1 :
Écrire un programme déterminant le nombre de lettres « e » (minuscules) présentes dans un texte de moins d’une ligne (supposée ne pas dépasser 132 caractères) fourni au clavier.
Exercice 3 :
Écrire un programme qui lit au clavier un mot (d’au plus 30 caractères) et qui l’affiche à l’envers.
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
Exemple où l’on demande l’exécution du programme nommé test, en lui transmettant les arguments arg1, arg2 et arg3 :
Ces paramètres sont toujours des chaînes de caractères (lorsqu’ils sont fournis dans une commande de lancement du programme, ils sont séparés par des espaces). Leur transmission à la fonction main (réalisée par le système) se fait selon les conventions suivantes :
11) Les arguments transmis à la fonction main
test arg1 arg2 arg3
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
nous obtiendrons :
Voici un exemple de programme utilisant ces possibilités.
11) Les arguments transmis à la fonction main
main (int nbarg, char * argv[])
Langage C
I. II. III. IV. V. VI. VII. VIII. IX.
Les chaînes de caractères
11) Les arguments transmis à la fonction main
#include <stdio.h>
#include <stdarg.h>
main(int nbarg, char * argv[])
{
int i ;
printf ("mon nom de programme est : %s\n", argv[0]) ;
if (nbarg > 1)
for (i = 1 ; i<nbarg ; i++)
printf ("argument numéro %d : %s\n", i, argv[i]) ;
else printf ("pas d’arguments\n") ;
}
LIGCOM
mon nom de programme est : LIGCOM
pas d’arguments
______________________________________
LIGCOM parametre
mon nom de programme est : LIGCOM
argument numéro 1 : parametre
______________________________________
LIGCOM entree.dat sortie 25CX9
mon nom de programme est : LIGCOM
argument numéro 1 : entree.dat
argument numéro 2 : sortie
argument numéro 3 : 25CX9