• Aucun résultat trouvé

Chapitre 10 : Chaînes de caractères

N/A
N/A
Protected

Academic year: 2022

Partager "Chapitre 10 : Chaînes de caractères"

Copied!
1
0
0

Texte intégral

(1)

Chapitre 10 : 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 est invalide :

urgent = "911" ;

urgent est le nom d'un tableau, il n'est pas une "lvalue"

(left value : valeur à gauche une affectation).

(2)

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

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.

(3)

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 :

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

fait afficher :

Numéro pour l'urgence : 911

(4)

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!".

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

(5)

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)

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.

(6)

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

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

(7)

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)

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

(8)

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

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

(9)

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'.

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'.

(10)

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

|_____|_____|_____|____|

*P

(11)

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 ;

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

(12)

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

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

(13)

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

}

(14)

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 J' aime

Tu aimes Il aime Nous aimons Vous aimez Ils aiment

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

&d0DExemple 4&d@ :

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

(15)

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

}

*P = '\0';

return destination ; }

(16)

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

Références

Documents relatifs

8-10 : la méthode .extend() ajoute en bout de liste tous les éléments de la liste passée en argument ; liste a alors trois éléments?. Dans les exemples qui suivent, on crée de

chaîne de caractères = suite d’octets Lecture fichier texte : lignes stockées dans une chaîne de caractères.. Lecture fichier binaire : données stockées dans une chaîne

chaîne de caractères = suite d’octets Lecture fichier texte : lignes stockées dans une chaîne de caractères.. Lecture fichier binaire : données stockées dans une chaîne

Lecture fichier binaire : données stockées dans une chaîne de caractères... 3.2 str : chaîne d’octets (pas

En C++, les chaînes de caractères sont stockées dans des variables de type string : string prenom = &#34;Robert&#34;; // string pour les chaînes de caractères.. Les chaînes

• En tapant entre guillemets la chaîne que vous voulez mettre dans votre tableau, le compilateur C calcule automatiquement la taille nécessaire... Création et initialisation de

Écrire une fonction est_Palindrome prenant pour paramètre une chaîne de caractères et renvoyant 1 s'il s'agit d'un palindrome non strict et 0

• Le traitement de liste est souvent réalisé à l’aide de fonctions récursives (il n’existe pas d’équivalent fonctionnel direct des boucles). • Calcul de la longueur