X. Tableaux et chaînes de caractères▲
X-A. Objectifs▲
En C, une chaîne de caractères est équivalente à un tableau de caractères. Ce chapitre introduit ces deux notions (chaînes et tableaux) tout en vous faisant approcher de la gestion de la mémoire.
X-B. Tableaux▲
X-B-1. Définition▲
Un tableau est un ensemble d'éléments rangés en mémoire dans des cases consécutives (voir Table 9.1). Un tableau peut être constitué de plusieurs lignes et colonnes. Nous n'utiliserons dans un premier temps que les tableaux à une seule ligne.
Numéro de case | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
Contenu | A | B | C | D | E | F | G | H |
Notez que les cases d'un tableau sont numérotées à partir de 0 en langage C.
X-B-2. Déclaration▲
Un tableau se déclare de la manière suivante :
<type> <nom du tableau> [<taille du tableau>];
/* Déclaration d'un tableau de 10 caractères */
char
tab_char [10
];
/* Déclaration d'un tableau de 10 entiers */
int
tab_int [10
];
X-B-3. Utilisation▲
On accède à une case du tableau en mettant le nom du tableau, suivi d'un crochet ouvrant « [ » puis un numéro de case et un crochet fermant : « ] ». Cela donne, par exemple :
/* déclarations */
int
tab_int[10
]; /* tableau de 10 cases (0 à 9) d'entiers */
char
tab_char[10
]; /* tableau de 10 cases (0 à 9) de caractères */
/* utilisation */
tab_char[3
]=
'
C
'
; /* Initialisation de la case 3 (la quatrième) de tab_char */
tab_int[6
]=
10
; /* Initialisation de la case 6 (la septième) de tab_int */
tab_int[7
]=
tab_int[6
] *
2
; /* La case 7 (la huitième) contiendra donc 20 (10*2) */
N'oubliez pas que le compilateur ne vérifie pas que vous utilisez le tableau dans ses limites. Il vous est donc possible d'écrire à l'extérieur de votre tableau, donc chez le voisin. C'est l'un des bugs les plus courants de la programmation en C.
X-C. Chaînes de caractères▲
Les chaînes de caractères sont des tableaux de caractères suivis du 0 (zéro ; ne pas confondre avec le caractère O de « Oh la la » par exemple…) qui est considéré lui aussi comme un caractère. Une chaîne s'écrit donc : contenu utile de la chaîne + valeur 0.
Caractère | 'E' | 'r' | 'i' | 'c' | '\0' |
Code ASCII | 69 | 114 | 105 | 99 | 0 |
Case | 0 | 1 | 2 | 3 | 4 |
Table 9.2 - Chaînes de caractères
X-C-1. Déclaration d'une chaîne de caractères▲
Une chaîne de caractères se déclare sous la forme d'un tableau de caractères de longueur fixe. Attention, comme signalé auparavant, si vous dépassez la longueur de tableau, vous écrivez chez le voisin.
Ainsi :
char
m_chaine [20
] ;
permettra d'enregistrer des chaînes de 19 caractères maximum (20-1 pour le 0 de fin de chaîne).
Il est possible de déclarer une chaîne de caractères sans en spécifier la longueur de départ de la façon suivante :
char
chaine [] =
"
Eric
"
;
De cette façon, la chaîne fera exactement la longueur nécessaire pour stocker « Eric » et le 0 final soit 4+1=5 octets.
X-C-2. Affichage d'une chaîne de caractères▲
Une chaîne de caractères s'affiche grâce à la commande printf et le format %s.
Ainsi :
printf
(
"
%s
"
,chaine);
affichera le contenu de chaine.
X-C-3. Longueur d'une chaîne de caractères▲
La longueur d'une chaîne de caractères s'obtient par la fonction strlen (disponible au travers de la bibliothèque string). Le 0 de fin de chaîne n'est pas compté dans cette longueur.
#include <stdio.h>
#include <string.h>
int
main (
) {
char
ch [] =
"
toto
"
;
printf
(
"
La longueur de %s est : %d
"
,ch,strlen
(
ch));
return
0
;
}
Affichera : « La longueur de toto est : 4 » à l'écran.
X-C-4. Initialisation d'une chaîne de caractères▲
Le format %p, que nous avons déjà vu, permet l'affichage d'un void *(pointeur sur un type void) et va nous servir par la suite à afficher les adresses mémoires…
Le programme suivant :
char
tab[10
];
printf
(
"
adresse où commence tab=%p
"
,&
tab[0
]);
affichera la même chose que ce programme :
char
tab[10
];
printf
(
"
adresse où commence tab=%p
"
,tab);
On voit donc que tab et &tab[0] sont égaux. En revanche, le programme suivant est incorrect :
char
tab[10
];
tab=
"
coucou
"
;
En effet, tab désigne l'adresse où débute le tableau en mémoire. Dans l'affectation tab="coucou"; le membre de gauche désigne une adresse alors que le membre de droite désigne une chaîne de caractères ; les deux n'étant pas du même type, le compilateur C le refuse…
Pour initialiser une chaîne de caractères, il est possible d'utiliser la fonction strcpy. Cette fonction nous impose une nouvelle fois d'ajouter le fichier d'en‐tête string.h :
#include <stdio.h>
#include <string.h>
int
main
(
void
) {
char
line[80
];
strcpy
(
line,"
un exemple de chaine initialisée...
"
);
printf (
"
%s
\n
"
,line);
return
0
;
}
Une recopie de la chaîne « un exemple de chaine initialisée… » caractère par caractère est effectuée en démarrant à l'adresse où line se trouve stockée en mémoire (le '\0'final est copié lui aussi).
Enfin, si l'on souhaite lire une chaîne directement au clavier, on peut utiliser la fonction scanf :
#include <stdio.h>
int
main
(
void
) {
char
line[80
];
printf
(
"
veuillez entrer votre chaine:
"
);
scanf
(
"
%s
"
,line);
/* scanf("%s",&line[0]) ferait la même chose */
printf
(
"
la chaine saisie vaut :%s
"
,line);
return
0
;
}
Notons que les chaînes de caractères saisies de cette manière ne peuvent comporter ni espaces, ni tabulations.
X-C-5. Exercices▲
Exercice n°9.1 — Affichez une chaine de caractères
Lisez l'intégralité de l'exercice avant de démarrer…
- En utilisant une boucle for, remplissez un tableau de 10 caractères avec les lettres de l'alphabet en commençant par A (code ASCII 65); le tableau devra donc contenir ceci :
Table 9.3 - Remplissez un tableau… Case 0 1 2 3 4 5 6 7 8 9 10 Contenu 'A' 'B' 'C' 'D' 'E' 'F' 'G' 'H' 'I' 'J' 0 - Faites afficher la chaîne de caractères ainsi obtenue ;
- Faites afficher chaque caractère du tableau sous la forme « Caractère n°0 : A ».
Il est possible d'écrire tab_car [i] = code_ascii; où code_asciiest un entier représentant le code Ascii du caractère désigné.
int
pos=
0
; /* Position dans le tableau */
printf (
"
Caractère numéro %d : %c
"
,pos, tab_car [pos]);
tab_car [la bonne position] =
0
;
ou encore (étant donné que le caractère '\0' désigne la même chose que 0) par :
tab_car [la bonne position] =
'
\0
'
;
On préfèrera généralement cette dernière solution qui est plus explicite et montre bien que l'on travaille avec des chaînes de caractères.
Enfin, voici un exemple de programme qui permet d'initialiser élégamment une chaîne de caractères à « ABCDEFGHIJKLMNOPQRSTUVWXYZ » puis de l'afficher à l'écran :
#include <stdio.h>
int
main (
) {
int
i=
0
;
int
pos_tab=
0
;
char
tab_alpha[27
];
for
(
i=
'
A
'
;i<=
'
Z
'
;i++
){
tab_alpha[pos_tab]=
i;
pos_tab++
;
}
tab_alpha[26
]=
0
;
printf
(
"
%s
\n
"
,tab_alpha);
return
0
;
}
X-C-6. La fonction gets : saisie d'une chaîne de caractères▲
La fonction gets permet de saisir une chaîne de caractères validée par la touche ENTREE. Attention, la touche ENTREE elle‐même n'est pas enregistrée dans le tableau de caractères.
Lorsque vous compilez votre programme par :
gcc -o essai essai.c
vous verrez peut être un avertissement du type :
warning : gets may be dangerous
Si c'est le cas, ne vous inquiétez pas. Le compilateur craint simplement qu'à l'exécution, l'utilisateur saisisse une chaîne de caractères qui soit plus longue que l'espace qui a été réservé pour la stocker (80 caractères dans l'exemple ci‐dessous), auquel cas des problèmes risquent d'apparaître. L'utilisation de gets est donc à proscrire dans un cadre « professionnel ».
#include <stdio.h>
int
main
(
void
) {
char
line[81
];
/* 81 : taille arbitraire supposée suffisante
Une ligne écran = 80 caractères + 1 case
pour le '\0' de fin de chaîne */
printf
(
"
Saisissez une chaîne de caractère :
\n
"
);
gets
(
line );
/* La frappe de l'utilisateur sera enregistrée dans
line, on suppose qu'il ne frappera pas plus de
80 caractères, sinon aïe aïe aïe */
printf
(
"
\n
La chaîne saisie est :
\n
%s
\n
"
, line );
return
0
;
}
Voici un exemple d'exécution :
Saisissez une chaîne de caractères :
Bonjour !
La chaîne saisie est :
Bonjour !
Notons qu'il n'y a qu'un seul passage à la ligne (celui affiché par la fonction printf).
X-C-7. Passage d'une chaîne de caractères en paramètres▲
Pour passer un tableau (et donc une chaîne de caractères) en paramètre à une fonction, nous devons simplement donner l'adresse du début du tableau. Les deux fonctions suivantes sont donc équivalentes :
nt ma_saisie (
char
chaine[]) {
/* ...Faire ce qu'il faut... */
return
0
;
}
int
main (
) {
char
ma_chaine [30
];
ma_saisie (
ma_chaine);
return
0
;
}
int
ma_saisie (
char
*
chaine) {
/* ...Faire ce qu'il faut... */
return
0
;
}
int
main (
) {
char
ma_chaine [30
];
ma_saisie (
ma_chaine);
return
0
;
}
En fait, dans la pratique, l'écriture suivante :
int
ma_saisie (
char
chaine[]) {
est équivalente à celle‐ci :
int
ma_saisie (
char
*
chaine) {
Nous reviendrons longuement, par la suite, sur cette quasi‐équivalence pointeurs/tableaux… ne vous inquiétez pas si vous ne comprenez pas tout pour l'instant…
X-D. Quelques fonctions utiles▲
X-D-1. La fonction strcat▲
La fonction strcat(<s>, <t>) ajoute la chaîne de caractères <t> à la fin de <s> (on appelle cela une concaténation).
Le programme suivant affichera la chaîne « Bonjour Paul » à l'écran :
#include <stdio.h>
#include <string.h>
int
main (
) {
char
chaine1[20
]=
"
Bonjour
"
;
char
chaine2[20
]=
"
Paul
"
;
strcat
(
chaine1,chaine2); /* ajoute chaine2 à la fin de chaine1 */
printf
(
"
%s
\n
"
,chaine1);
return
0
;
}
On remarquera qu'il est important de dimensionner chaine1 à une taille suffisante, sans quoi on pourrait avoir des difficultés pour stocker la chaîne « Bonjour Paul » dans chaine1.
X-D-2. La fonction strncpy▲
La fonction strncpy(<s>, <t>, <n>) est presque similaire à strcpy mais copie au plus <n> caractères de la chaîne <t> au début de <s>.
#include <stdio.h>
#include <string.h>
int
main (
) {
char
chaine1[20
]=
"
Bonjour
"
;
char
chaine2[20
]=
"
Edouard
"
;
strncpy
(
chaine1,chaine2,2
); /* recopie 2 caractères de chaine2 à l'adresse de chaine1 */
printf
(
"
%s
\n
"
,chaine1);
return
0
;
}
…affichera :
Ednjour
X-D-3. La fonction strncat▲
La fonction strncat(<s>, <t>, <n>)ajoute au plus <n> caractères de la chaîne <t> à la fin de <s>.
#include <stdio.h>
#include <string.h>
int
main (
) {
char
chaine1[20
]=
"
Bonjour
"
;
char
chaine2[20
]=
"
Edouard
"
;
strncat
(
chaine1,chaine2,2
); /* ajoute les 2 premiers caractères de chaîne2 à la fin de chaine1 */
printf
(
"
%s
\n
"
,chaine1);
return
0
;
}
…affichera :
Bonjour Ed
X-D-4. La fonction strcmp▲
La fonction strcmp(<s>, <t>) compare les chaînes de caractères <s> et <t> de manière lexicographique et fournit un résultat :
- nul (0) si <s> est égale à <t>
- négatif si <s> précède <t>. Par exemple, strcmp("AAAA","BBBB") renverrait ‐1
- positif si <s> suit <t>. Par exemple, strcmp("BBBB","AAAA") renverrait +1
X-D-5. Les fonctions sprintf et sscanf▲
Nous terminerons par deux fonctions très utiles.
sprintf(<chaine cible>,<chaine de formatage>,<expr1>,<expr2>,…)
La fonction sprintf renvoie une valeur négative en cas d'erreur et le nombre de caractères stockés dans la chaîne cible sinon.
char
s[200
];
int
i=
15
;
int
code;
code=
sprintf
(
s,"
%d
"
,i);
char
s[]=
"
12.5 12.3 11.6
"
;
float
a,b,c;
int
code;
code=
sscanf
(
s,"
%f%f%f
"
,&
a,&
b,&
c);
Les variables numériques a, b et c contiendront respectivement : 12.5 12.3 et 11.6.
En cas d'erreur, sscanf renvoie une valeur négative. S'il n'y a pas eu d'erreur, c'est le nombre de variables affectées qui est renvoyé.
X-E. Tableaux à 2 dimensions▲
Un tableau à 2 dimensions se déclare de la façon suivante :
<type> <nom du tableau> [<taille dimension 1>] [<taille dimension 2>] ;
int
table[5
][5
]; /* représente un tableau d'entiers de 5 lignes et 5 colonnes.*/
Ou bien :
float
tab[3
][2
]=
{{
1
.2
, -
1
.3
}
,
{
8
.5
, 12
.4
}
,
{
-
123
.0
, 4
.0
}}
;
Voici à présent un programme qui affiche le contenu d'un tableau à deux dimensions :
#include <stdio.h>
int
main (
) {
int
tab[5
][10
];
int
i,j;
/* Pour chaque ligne ... */
for
(
i=
0
; i<
5
; i++
){
/* ... considérer chaque case */
for
(
j=
0
; j<
10
; j++
)
printf
(
"
%d
"
, tab[i][j]);
/* Retour à la ligne */
printf
(
"
\n
"
);
}
return
0
;
}
Si on souhaite initialiser ce tableau avec des valeurs lues au clavier, voici comment faire :
#include <stdio.h>
int
main (
) {
int
tab[5
][10
];
int
i,j;
/* Pour chaque ligne ... */
for
(
i=
0
; i<
5
; i++
){
/* ... considérer chaque case */
for
(
j=
0
; j<
10
; j++
)
scanf
(
"
%d
"
, &
tab[i][j]);
/* Retour à la ligne */
printf
(
"
\n
"
);
}
return
0
;
}
#include <stdio.h>
#define LIGNES 5
#define COLONNES 10
int
main (
) {
int
tab[LIGNES][COLONNES];
int
i,j;
/* Pour chaque ligne ... */
for
(
i=
0
; i<
LIGNES; i++
){
/* Considérer chaque case */
for
(
j=
0
; j<
COLONNES; j++
)
scanf
(
"
%d
"
, &
tab[i][j]);
/* Retour à la ligne */
printf
(
"
\n
"
);
}
return
0
;
}
L'usage de #define LIGNES 5 demande au compilateur de parcourir tout le programme et de faire une sorte de chercher‐remplacer : chercher la chaîne LIGNES et remplacer par 5. Il fera ensuite pareil pour COLONNES.
Il ne faut pas mettre des « ; » à la fin des #define.
#include <stdio.h>
#define LIGNES 5;
#define COLONNES 10;
En effet, les rechercher‐remplacer aboutiraient au programme suivant qui ne se compilerait pas :
int
main (
) {
int
tab[5
;][10
;];/* compile pas !!! */
int
i,j;
/* Pour chaque ligne ... */
for
(
i=
0
; i<
5
;; i++
){
/* compile pas !!! */
/* ... considérer chaque case */
for
(
j=
0
; j<
10
;; j++
)/* compile pas !!! */
scanf
(
"
%d
"
, tab[i][j]);
/* Retour à la ligne */
printf
(
"
\n
"
);
}
return
0
;
}
X-F. Correction des exercices▲
Corrigé de l'exercice n°9.1 — Affichez une chaine de caractères
#include <stdio.h>
#include <stdlib.h>
int
main (
) {
/* 10 caractères + 0 de fin de chaîne */
char
tab [11
];
int
i=
0
; /* compteur */
/* Remplissage du tableau avec les caractères */
for
(
i=
0
; i<
10
; i++
)
tab[i] =
65
+
i; // ou tab[i]='A'+i;
/* Ajout du 0 de fin de chaine*/
tab[10
] =
0
;
/* Affichage de la chaîne*/
printf
(
"
tab : %s
\n
"
,tab);
/* Saut d'une autre ligne */
printf
(
"
\n
"
);
/* Affichage de chacun des caractères */
for
(
i=
0
; i<
10
; i++
)
printf
(
"
Caractère numero %d: %c
\n
"
,i,tab [i]);
return
0
;
}
X-G. À retenir▲
Voici pour finir un petit programme qui reprend l'essentiel de ce qui a été vu. Il permet de lire une chaîne de caractères (chaine1) au clavier puis de recopier cette chaîne dans une autre (chaine2) et de l'afficher à l'écran :
#include <stdio.h>
#include <string.h>
int
main (
) {
char
chaine1[81
]; /* 80 caractères + '\0' */
char
chaine2[81
];
printf
(
"
Veuillez entrer votre chaine de caractères :
"
);
scanf
(
"
%s
"
,chaine1); /* identique à scanf("%s",&chaine1[0]); */
strcpy
(
chaine2,chaine1); /* !!! attention à l'ordre !!! */
printf
(
"
chaine2 vaut: %s
\n
"
,chaine2);
strcpy
(
chaine1,""
); /* et pas chaine1=""; !!!!!!! */
strcat
(
chaine1,"
Pierre
"
);
printf
(
"
Veuillez entrer votre chaine de caractères
"
);
scanf
(
"
%s
"
,chaine2);
strcat
(
chaine1,chaine2);
strcat
(
chaine1,"
Paul Jacques...
"
);
printf
(
"
chaine1 vaut: %s
\n
"
,chaine1);
return
0
;
}