1 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

CHAPITRE VIII

2 of 36

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.

      • Le compilateur représente les chaînes constantes (entre doubles quottes)
      • Utilisation des fonctions qui permettent de réaliser :
        • Des lectures ou écritures de chaînes ;
        • Des traitements classiques tels que concaténation, recopie, comparaison, extraction de sous-chaîne, conversions.
      • Utilisation de tableaux de caractères pour traiter les chaines de caractères

3 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

    • Convention adoptée
      • Une chaîne de caractères est représentée par une suite d’octets correspondant à chacun de ses caractères
      • Elle est terminé par un octet supplémentaire de code nul.
      • Une chaîne de n caractères occupe en mémoire n+1 octets.

​

    • Cas des chaînes constantes

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

4 of 36

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

5 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

    • Initialisation de tableaux 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' }

6 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

    • Initialisation de tableaux 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" ;

7 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

    • Initialisation de tableaux de pointeurs sur des chaînes

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" } ;

8 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

    • Initialisation de tableaux de pointeurs sur des chaînes

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

9 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

    • Initialisation de tableaux de pointeurs sur des chaînes

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

10 of 36

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 :

      • l’utilisation du code de format %s dans les fonctions printf et scanf ;
      • les fonctions spécifiques de lecture (gets) ou d’affichage (puts) d’une chaîne (une seule à la fois).

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

11 of 36

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.

      • le code %s de scanf, utilise les délimiteurs habituels (l’espace ou la fin de ligne). Cela interdit la lecture d’une chaîne contenant des espaces. De plus, le caractère délimiteur n’est pas consommé : il reste disponible pour une prochaine lecture ;
      • avec gets, seule la fin de ligne sert de délimiteur. Ici le caractère de fin de ligne est effectivement consommé : il ne risque pas d’être pris en compte lors d’une nouvelle lecture.

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

12 of 36

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

13 of 36

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 :

      • lecture d’une chaîne de caractères par gets (c’est-à-dire d’une suite de caractères quelconques validés par « return ») ;
      • décodage de cette chaîne suivant un format, à l’aide de la fonction sscanf.

​

​

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)

14 of 36

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

15 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

    • Ces fonctions travaillent toujours sur des adresses

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);

16 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

    • La fonction strlen (string.h)

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

17 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

    • La fonction strcat (string.h)

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.

  • La première permet de réserver un emplacement plus grand que la constante chaîne qu’on y place initialement.

18 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

    • La fonction strncat (string.h)

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) ;

}

19 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

    • La fonction strcmp (string.h)

​

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

      • positive si chaîne1 > chaîne2 (si chaîne1 arrive après chaîne2, au sens de l’ordre défini par le code des caractères) ;
      • nulle si chaîne1 = chaîne2 (si ces deux chaînes contiennent exactement la même suite de caractères) ;
      • négative si chaîne1 < chaîne2.

Exemple

6) Les fonctions de comparaison de chaînes

strcmp ( chaîne1, chaîne2 )

strcmp ("bonjour", "monsieur");

​

strcmp ("paris2", "paris10");

négatif

positif

20 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

    • La fonction strncmp (string.h)

​

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

21 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

    • La fonction stricmp & strnicmp (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).

6) Les fonctions de comparaison de chaînes

stricmp ( chaîne1, chaîne2 )

strnicmp ( chaîne1, chaîne2, lgmax )

22 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

    • strcpy ( but, source ) (string.h)

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.

​

    • strncpy ( but, source, lgmax ) (string.h)

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

23 of 36

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

24 of 36

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.

​

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

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

​

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

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.

​

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

recherche, dans chaîne, la première occurrence complète de la sous-chaîne.

​

8) Les fonctions de recherche dans une chaîne

25 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

    • Conversion d’une chaîne en valeurs numériques

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.

​

      • atoi ( chaîne ) (stdlib.h)

fournit un résultat de type int.

      • atol ( chaîne ) (stdlib.h)

fournit un résultat de type long.

      • atof ( chaîne ) (stdlib.h)

fournit un résultat de type double.

9) Les fonctions de conversion

26 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

    • Conversion de valeurs numériques en chaîne

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

27 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

    • Une chaîne possède une vraie fin, mais pas de vrai début

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

28 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

​

​

​

​

​

​

    • Les risques de modification des chaînes constantes

​

​

​

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 ? */

29 of 36

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'";

30 of 36

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) ;

}

31 of 36

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 */

}

32 of 36

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.

33 of 36

Exercice 3 :

Écrire un programme qui lit au clavier un mot (d’au plus 30 caractères) et qui l’affiche à l’envers.

34 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

    • Comment passer des arguments à un programme

Exemple où l’on demande l’exécution du programme nommé test, en lui transmettant les arguments arg1, arg2 et arg3 :

​

​

    • Comment récupérer ces arguments dans la fonction main

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 :

      • le premier argument reçu par main sera de type int et il représentera le nombre total de paramètres fournis dans la ligne de commande (le nom du programme compte lui-même pour un paramètre),
      • le second argument reçu par main sera l’adresse d’un tableau de pointeurs, chaque pointeur désignant la chaîne correspondant à chacun des paramètres.

​

11) Les arguments transmis à la fonction main

test arg1 arg2 arg3

​

35 of 36

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

Les chaînes de caractères

​

nous obtiendrons :

      • dans nbarg, le nombre total de paramètres ;
      • à l’adresse argv[0], le premier paramètre, c’est-à-dire le nom du programme
      • à l’adresse argv[1], le second paramètre (dans exemple, la chaîne arg1) ;
      • etc.

Voici un exemple de programme utilisant ces possibilités.

​

11) Les arguments transmis à la fonction main

main (int nbarg, char * argv[])

36 of 36

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