Top Banner
Chapitre 4 : Chaînes de caractères En C, on peut présenter une chaîne de caractères sous forme de : 1. tableau des caractères : char nom [20] ; ou de 2. pointeur vers le type caractère : char * telephone ; 1) Schéma de représentation d'une chaîne de caractères : Si la valeur d'une chaîne de caractères nommée urgent vaut "911" par exemple, on la présente avec le schéma suivant : | '9' | '1' | '1' |'\0'| urgent -----> |_____|_____|_____|____| La chaîne se termine par le caractère invisible '\0' qui marque sa fin. 2) Déclaration, initialisation et affectation : Écrire d'autres manières différentes pour déclarer la chaîne urgent et donner la valeur "911" à cette chaîne. Solution : 1. Sous forme tableau des caractères : a. Manière 1 : char urgent[4] ; /* pour le caractère '\0' aussi */ strcpy(urgent, "911"); /* string copy : copie une chaîne à une autre chaîne (string.h) */ Il est intéressant de noter que l'affectation suivante Chapitre 4 : Fichiers de type texte Page 83
24

Chapitre 4 : Chaînes de caractères

Jan 28, 2023

Download

Documents

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Chapitre 4 : Chaînes de caractères

Chapitre 4 : Chaînes de caractères

En C, on peut présenter une chaîne de caractères sous forme de :

1. tableau des caractères : char nom [20] ;

ou de 2. pointeur vers le type caractère : char * telephone ;

1) Schéma de représentation d'une chaîne de caractères :

Si la valeur d'une chaîne de caractères nommée urgent vaut "911" par exemple, on la présente avec le schéma suivant :

| '9' | '1' | '1' |'\0'| urgent -----> |_____|_____|_____|____|

La chaîne se termine par le caractère invisible '\0' qui marque sa fin.

2) Déclaration, initialisation et affectation :

Écrire d'autres manières différentes pour déclarer la chaîne urgent et donner la valeur "911" à cette chaîne.

Solution :

1. Sous forme tableau des caractères :

a. Manière 1 :

char urgent[4] ; /* pour le caractère '\0' aussi */

strcpy(urgent, "911"); /* string copy : copie une chaîne à une autre chaîne (string.h) */

Il est intéressant de noter que l'affectation suivante

Chapitre 4 : Fichiers de type texte Page 83

Page 2: Chapitre 4 : Chaînes de caractères

est invalide :

urgent = "911" ;

urgent est le nom d'un tableau, il n'est pas une "lvalue" (left value : valeur à gauche une affectation).

b. Manière 2 : déclarer et "initialiser"

char urgent[4] = "911" ;

c. Manière 3 : déclarer et "initialiser"

char urgent[4] = { '9', '1', '1', '\0' } ;

d. Manière 4 : déclarer et "affecter"

char urgent[4] ;

urgent[0] = '9' ; urgent[1] = '1' ; urgent[2] = '1' ; urgent[3] = '\0';

e. Manière 5 : déclarer et lire sa valeur

char urgent[4] ;

printf("Quel est le numéro pour l'urgence ? "); scanf("%s", urgent); /* ou gets(urgent) ; avec <string.h> */

Notez que la lecture avec scanf n'est pas assez pratique :

char nomPre [20] ; printf("Entrez le nom et prénom ");

scanf("%s", nomPre);

Chapitre 4 : Fichiers de type texte Page 84

Page 3: Chapitre 4 : Chaînes de caractères

printf("Le nom et prénom lu : %s\n", nomPre);

Si le nom et prénom tapé est Cloutier Gilles la valeur de nomPre est "Cloutier" seulement! : l'espace entre Cloutier et Gilles provoque la fin de la saisie. On perd une partie des informations.

Chapitre 4 : Fichiers de type texte Page 85

Page 4: Chapitre 4 : Chaînes de caractères

2. Sous forme pointeur vers le type char

char * urgent ;

On peut faire des choses semblables comme avec un tableau des caractères :

char * urgent = "911" ; OU

char * urgent ; ...... strcpy(urgent , "911"); OU

char * urgent ; ...... gets(urgent);

De plus, on peut affecter (qui n'est pas le cas d'un tableau) :

urgent = "911" ; /* correct ici! */

Cependant, il est préférable d'allouer la mémoire avant de faire l'affectation et surtout de la lecture :

urgent = (char *) malloc (4) ; /* avec <stdlib.h> */

urgent = "911" ;

3) Affichage du contenu d'une chaîne de caractères :

Soit char * urgent = "911" ; OU char urgent[4] = "911" ;

Longueur d'une chaîne (strlen : string length) :

strlen("911") vaut 3 (ne pas tenir compte de '\0') strlen(urgent) vaut 3

Affichage d'une chaîne (code de format %s) :

L'instruction :

Chapitre 4 : Fichiers de type texte Page 86

Page 5: Chapitre 4 : Chaînes de caractères

printf("Numéro pour l'urgence : %s\n", urgent);

fait afficher :

Numéro pour l'urgence : 911

Mise en garde :

L'instruction :

printf("Numéro pour l'urgence : %c\n", *urgent);

fait afficher seulement :

Numéro pour l'urgence : 9

Pourquoi ?

urgent est un pointeur vers le type char :

| '9' | '1' | '1' |'\0'| urgent -------> |_____|_____|_____|____|

*urgent

*urgent est de type char, *urgent vaut '9' ici.

4) La concaténation des chaînes de caractères :

char * ch1 , * ch2 ;

ch1 = (char *) malloc(80); ch1 = "Bonjour ";

ch2 = "tout le monde!";

Après l'instruction :

strcat(ch1, ch2) ;

ch1 vaut "Bonjour tout le monde!".

Chapitre 4 : Fichiers de type texte Page 87

Page 6: Chapitre 4 : Chaînes de caractères

Après l'instruction :

strncat(ch1, ch2, 3) ;

ch1 vaut "Bonjour tou".

5) La copie des chaînes de caractères :

a) char * strcpy(char * destination, char * source)

Exemple :

... strcpy(nomPre,"LALIBERTE PIERRE"); printf("%s", nomPre); Le bloc affiche : LALIBERTE PIERRE

b) char * strncpy (char * destination,char * source, int k) (on copie jusqu'à k caractères au maximum)

Exemple :

... strncpy(nomPre,"LALIBERTE PIERRE",4); printf("%s", nomPre);

Le bloc affiche : LALI

6) La comparaison des chaînes de caractères :

a) int strcmp(char * chaine1, char * chaine2)

valeur retournée par la fonction signification < 0 chaine1 < chaine2 0 chaine1 = chaine2 > 0 chaine1 > chaine2

Exemple :

... strcmp("Bon", "Bourse") est inférieur à 0 car 'n' < 'u' (les 2ères lettres sont pareilles)

Chapitre 4 : Fichiers de type texte Page 88

Page 7: Chapitre 4 : Chaînes de caractères

strcmp("Bon", "Bon") vaut 0

strcmp("papa", "GRAND") est supérieur à zéro car 'p' > 'G' (code ASCII)

b) int strncmp(char * chaine1,char * chaine2, int k)

Comme strcmp en se limitant aux k premiers caractères.

Exemple :

... strncmp("Bon", "Bourse", 2) est 0

strncmp("Bon", "Bourse", 3) est < 0

etc ...

c) int stricmp (char * chaine1, char * chaine2) int strincmp(char * chaine1, char * chaine2, int k)

Elles fonctionnent comme les deux dernières fonctions sans tenir compte de la différence entre les majuscules et les minuscules. Exemple :

... strincmp("Bon", "bobo", 2) est 0

7) La recherche dans une chaîne de caractères :

a) char * strchr(char * chaine, char unCar)

valeur retournée par la fonction signification un pointeur NULL unCar ne fait pas partie de la chaîne

un pointeur non NULL unCar fait partie qui pointe vers le 1er de la chaîne caractère trouvé à partir du début de la chaîne

Chapitre 4 : Fichiers de type texte Page 89

Page 8: Chapitre 4 : Chaînes de caractères

Exemple :

... do { printf("Tapez votre choix parmi les options A, T ou Q "); fflush(stdin); choix = getchar();

if (strchr("ATQ", choix) == NULL) printf("choix invalide\n"); } while ( strchr("ATQ", choix) == NULL );

...

Avec char * P ; et P = strchr("Bonsoir", 'o');

on a : | P (non NULL) | v | 'B' | 'o' | 'n' | 's' | 'o' | 'i' | 'r' |'\0'| |_____|_____|_____|_____|_____|_____|_____|____|

b) char * strrchr(char * chaine,char unCar)

Elle fonctionne comme strchr en examinant la chaîne à partir de la fin :

Avec char * P ; et

P = strrchr("Bonsoir", 'o');

Chapitre 4 : Fichiers de type texte Page 90

Page 9: Chapitre 4 : Chaînes de caractères

on a : | P (non NULL) | v | 'B' | 'o' | 'n' | 's' | 'o' | 'i' | 'r' |'\0'| |_____|_____|_____|_____|_____|_____|_____|____|

c) char * strstr(char * chaine, char * sousChaine)

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

Exemple :

Avec char * P ; et

P = strstr("Bonsoir", "so");

on a : | P (non NULL) | v | 'B' | 'o' | 'n' | 's' | 'o' | 'i' | 'r' |'\0'| |_____|_____|_____|_____|_____|_____|_____|____|

8) La conversion :

a) MAJUSCULE et minuscule :

strupr (chaine); ==> la chaîne sera en majuscule

strlwr (chaine); ==> la chaîne sera en minuscule

b) chaîne de caractères en valeur numérique :

int atoi (char * chaine) : chaîne en entier long atol (char * chaine) : chaîne en "long" entier double atof (char * chaine) : chaîne en double (grand réel)

Chapitre 4 : Fichiers de type texte Page 91

Page 10: Chapitre 4 : Chaînes de caractères

c) valeur numérique en chaîne de caractères :

char * itoa(int n, char * chaine, int base) :

un entier dans une base (2 à 36 dont 10 est la base décimale) en chaîne de caractères

Chapitre 4 : Fichiers de type texte Page 92

Page 11: Chapitre 4 : Chaînes de caractères

char * ltoa(long n, char * chaine, int base) :

un long entier dans une base (2 à 36 dont 10 est la base décimale) en chaîne de caractères

9) La lecture dans un fichier texte :

Exemple d'un fichier de données de type texte :

LONGPRE LISE 1.67 58.6 CHARTRAND ANDRE 1.72 75.4 etc ...

La lecture :

#define LONG_NP 31 char nomPre[LONG_NP] ; /* y compris le caractère '\0' */ .....

while (!feof(donnees)) { fgets (nomPre, LONG_NP, donnees); /* dans <string.h> */ fscanf(donnees,"%f%f\n", &Taille, &Poids);

etc ...

}

10) Traitement d'une chaîne par soi-même :

1. Arithmétique des pointeurs :

a. Soient les déclarations suivantes :

int t[4] = { 5, 10, 15, 20 }, * P = t ;

P est un pointeur vers t[0] (car t vaut &t[0]) :

P | Adresse (2 octets pour └----------> ╔═══════════════╗ 178 mémoriser 1 entier) t[0] ║ 5 ║ 179

Chapitre 4 : Fichiers de type texte Page 93

Page 12: Chapitre 4 : Chaînes de caractères

╔═══════════════╗ 180 t[1] ║ 10 ║ 181 ╔═══════════════╗ 182 t[2] ║ 15 ║ 183 ╔═══════════════╗ 184 t[3] ║ 20 ║ 185 ╔═══════════════╗

En C, P + 2 par exemple a un sens, c'est l'adresse de t[2] (182 sur le schéma) :

P + 2 = P + 2 * (sizeof(*P)) (*P est de type int) = 178 + 2 * 2 = 182 (c'est l'adresse de t[2])

Ainsi :

P++ ; qui est équivalent à P = P + 1 ;

fait pointer le pointeur P vers l'élément suivant (t[1])

b. Soient les instructions suivantes :

char * ch = "Bonsoir" , * P = ch ;

| 'B' | 'o' | 'n' | 's' | 'o' | 'i' | 'r' |'\0'| P -----> |_____|_____|_____|_____|_____|_____|_____|____|

L'instruction :

if (*P++) printf("%c", *P);

fait afficher la lettre 'o' à l'écran et fait avancer le pointeur P vers le caractère 'o' :

Notez que if ( *P++ ) <===> if (*P != '\0' , P++)

Comme *P est 'B' qui n'est pas '\0', la condition est vraie et P++ fait pointer P vers 'o'.

Chapitre 4 : Fichiers de type texte Page 94

Page 13: Chapitre 4 : Chaînes de caractères

P | 'B' | 'o' | 'n' | 's' | 'o' | 'i' | 'r' |'\0'| | |_____|_____|_____|_____|_____|_____|_____|____| | ^ | | └---------------------┘

Ainsi, printf("%c", *P) ; fait afficher le caractère pointé par P, c'est la lettre 'o'.

Chapitre 4 : Fichiers de type texte Page 95

Page 14: Chapitre 4 : Chaînes de caractères

2. Parcourir tous les caractères d'une chaîne :

a. On utilise souvent la longueur et les indices :

char souhaite[30] = "Bonne chance!"; /* Ou char * souhaite = "Bonne chance!" ; */

int longueur = strlen(souhaite), i ;

for ( i = 0 ; i < longueur ; i++)

printf("%c", souhaite[i]);

b. On utilise la notion de pointeur :

char * urgent = "911" , * P ;

P = urgent ;

while (*P) printf("%c", *P++);

Notez que la valeur de *P est le caractère pointé par P et que (*P) est équivalent à (*P != '\0').

De plus, P++ permet de faire pointer P vers le prochaine caractère.

Au début :

| '9' | '1' | '1' |'\0'| P -----> |_____|_____|_____|____| *P

Comme *P vaut '9' qui est différent de '\0', on affiche la valeur de *P, c'est 9 et on fait pointer P vers le prochaine caractère :

P ────────┐ v

| '9' | '1' | '1' |'\0'| |_____|_____|_____|____|

Chapitre 4 : Fichiers de type texte Page 96

Page 15: Chapitre 4 : Chaînes de caractères

*P

Chapitre 4 : Fichiers de type texte Page 97

Page 16: Chapitre 4 : Chaînes de caractères

Comme *P vaut '1' qui est différent de '\0', on affiche la valeur de *P, c'est 1 et on fait pointer P vers le prochaine caractère :

P ───────────────┐ v | '9' | '1' | '1' |'\0'| |_____|_____|_____|____| *P

etc ....

3. Déterminer la longueur d'une chaîne par soi-même :

int longueur ( const char * chaine ) { int N = 0 ;

while (*chaine++) N++;

return N;

}

Exercice :

Simuler la fonction avec la chaîne : "Bonsoir".

11) Exemples et exercices :

Exemple 1 :

Écrire un bloc d'énoncés permettant d'afficher les 7 journées de la semaine comme suit :

Journée 1 : dimanche Journée 2 : lundi etc ....

Solution :

int rang ;

Chapitre 4 : Fichiers de type texte Page 98

Page 17: Chapitre 4 : Chaînes de caractères

char * jours[7] = { "dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi" };

for ( rang = 0 ; rang < 7 ; rang++)

printf("Journée %d : %s\n", rang+1, jours[rang]);

Exemple 2 :

Écrire un programme permettant de saisir une chaîne de caractères tapés au clavier, d'afficher la chaîne, de vérifier et d'afficher si la chaîne est un palindrôme (même lecture dans deux sens : exemple "Laval").

Solution :

#include <stdio.h> #include <stdlib.h> #include <alloc.h> #include <string.h>

int palindrome ( char chaine[] ) { int i , j , n = strlen(chaine);

strupr(chaine); /* convertir en MAJUSCULE */

for ( i = 0, j = n - 1 ; i < j ; i++, j-- ) if ( chaine[i] != chaine[j] ) return 0 ;

return 1 ; }

void main () { char * ch ;

ch = (char *) malloc(90) ; /* allouer la mémoire */ printf("Tapez une chaîne de caractères "); gets(ch);

Chapitre 4 : Fichiers de type texte Page 99

Page 18: Chapitre 4 : Chaînes de caractères

printf("La chaine %s %s\n", ch, palindrome(ch) ? " est un palindrôme" : " n'est pas un palindrôme " );

}

Exercice 1 :

Soient les instructions suivantes : char * ch = "Bonsoir" , * P = ch ; int N = 0 ; Quel est le rôle de N dans le bloc d'instructions suivantes ? :

while (*P) if ( strchr("AEIOUY", toupper(*P++)) ) N++ ;

Chapitre 4 : Fichiers de type texte Page 100

Page 19: Chapitre 4 : Chaînes de caractères

Exemple 3 :

Écrire un programme qui permet de saisir le nom d'un verbe régulier du premier groupe (ex. chanter, aimer, ...). Le programme conjugue le verbe au présent de l'indicatif.

Solution :

#include <stdio.h> #include <stdlib.h> #include <alloc.h> #include <string.h> #include <ctype.h>

void obtenir( char * verbe ) /* verbe régulier (pas manger ==> nous mangeons à la place de nous mangeons), premier groupe (se termine par er (comme aimer) */ { char * P ;

do { printf("Entrez le nom d'un verbe régulier du 1er groupe "): gets(verbe);

P = strstr(verbe, "er") ; if (!P) printf("%s n'est pas du premier groupe\n", verbe); } while (!P); }

void conjuger(char * verbe) { char * base ; int i, k ;

k = strlen(verbe); base = (char *) malloc(k-2); for ( i = 0 ; i < k-2 ; i++ ) base[i] = verbe[i]; base[k-2] = '\0';

printf("\n\nPrésent de l'indicatif du verbe %s\n", verbe);

if (strchr("AEIOUY", toupper(*verbe)))

Chapitre 4 : Fichiers de type texte Page 101

Page 20: Chapitre 4 : Chaînes de caractères

printf("J' "); else printf("Je "); printf("%se\n", base);

printf("Tu %ses\n", base); printf("Il %se\n", base); printf("Nous %sons\n", base); printf("Vous %sez\n", base); printf("Ils %sent\n", base); } void main() { char * verbe ; do { verbe = (char *) malloc(80); obtenir(verbe); conjuger (verbe);

printf("Avez-vous un autre verbe à conjuger ? (O/N) "); fflush(stdin); } while ( toupper(getchar()) == 'O'); }

Exécution :

Entrez le nom du verbe régulier du 1er groupe chanter

Présent de l'indicatif du verbe chanter Je chante Tu chantes Il chante Nous chantons Vous chantez Ils chantent

Avez-vous un autre verbe à conjuger ? (O/N) o

Entrez le nom d'un verbe régulier du 1er groupe aimer

Présent de l'indicatif du verbe aimer

Chapitre 4 : Fichiers de type texte Page 102

Page 21: Chapitre 4 : Chaînes de caractères

J' aime Tu aimes Il aime Nous aimons Vous aimez Ils aiment

Avez-vous un autre verbe à conjuger ? (O/N) n

Exemple 4:

Écrire votre "propre fonction" qui joue le rôle de la fonction "strcat" (concaténation de chaînes de caractères, page 87).

Chapitre 4 : Fichiers de type texte Page 103

Page 22: Chapitre 4 : Chaînes de caractères

Solution :

char * concat ( char * destination, const char * source ) { char * P = destination + strlen(destination) ;

while (*source) *P++ = *source++ ;

*P = '\0';

return destination ; }

Notes :

L'instruction : while (*source) *P++ = *source++ ;

peut s'écrire plus court encore comme suit :

while (*P++ = *source++) ;

dont l'expression entre ( et ) est évaluée comme suit :

P = source ; /* une affectation */

*P est-il différent de '\0' (condition sous while)

source++ ; /* vers le caractère suivant */ P++ ; /* vers le caractère suivant */

Une version plus "compréhensible" de cette fonction est :

char * concat ( char * destination, const char * source ) { char * P = destination ;

while (*P != '\0') P++ ;

while (*source != '\0') { *P = *source ; P++ ; source++;

Chapitre 4 : Fichiers de type texte Page 104

Page 23: Chapitre 4 : Chaînes de caractères

}

*P = '\0';

return destination ;

}

Chapitre 4 : Fichiers de type texte Page 105

Page 24: Chapitre 4 : Chaînes de caractères

Exercice 2 :

Écrire vos "propres fonctions" qui jouent le rôle de :

1. la fonction "strcpy" (copie de chaînes de caractères)

2. la fonction "strstr" (une chaîne est-elle une sous-chaîne d'une autre chaîne ?)

3. la fonction "strlwr" (conversion toute la chaîne en minuscules).

Chapitre 4 : Fichiers de type texte Page 106