Le C en 20 heures


précédentsommairesuivant

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. 

Table 9.1 - Tableau de caractères
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 :

 
Sélectionnez
<type> <nom du tableau> [<taille du tableau>];
 
Sélectionnez
/* 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 :

 
Sélectionnez
/* 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.

« Eric » s'écrit dans un tableau de 5 caractères de la façon suivante (l'usage du \0 sera expliqué par la suite) : 
Table 9.2 - Chaînes de caractères
Caractère'E''r''i''c''\0'
Code ASCII 69114105990
Case01234

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 :

 
Sélectionnez
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 :

 
Sélectionnez
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 :

 
Sélectionnez
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.

 
Sélectionnez
#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 :

 
Sélectionnez
char tab[10];
printf("adresse  commence tab=%p",&tab[0]);

affichera la même chose que ce programme :

 
Sélectionnez
char tab[10];
printf("adresse  commence tab=%p",tab);

On voit donc que tab et &tab[0] sont égaux. En revanche, le programme suivant est incorrect :

 
Sélectionnez
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 :

 
Sélectionnez
#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 :

 
Sélectionnez
#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

Image non disponible 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…
    Case012345678910
    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;code_ascii est un entier représentant le code Ascii du caractère désigné.

Pour faire afficher un seul caractère, on utilisera la syntaxe suivante :
 
Sélectionnez
int pos=0; /* Position dans le tableau */
printf ("Caractère numéro %d : %c",pos, tab_car [pos]);
La valeur 0 peut être assignée à un élément de tableau de la façon suivante :
 
Sélectionnez
tab_car [la bonne position] = 0;

ou encore (étant donné que le caractère '\0' désigne la même chose que 0) par :
 
Sélectionnez
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 :

 
Sélectionnez
#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 :

 
Sélectionnez
gcc -o essai essai.c

vous verrez peut être un avertissement du type :

 
Sélectionnez
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 ».

 
Sélectionnez
#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( "\nLa chaîne saisie est : \n%s\n", line );
   return 0;
}

Voici un exemple d'exécution :

 
Sélectionnez
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 :

 
Sélectionnez
nt ma_saisie (char chaine[]) {
   /* ...Faire ce qu'il faut... */  
   return 0;
}
int main () {
   char ma_chaine [30];
   ma_saisie (ma_chaine);
   return 0;
}
 
Sélectionnez
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 :

 
Sélectionnez
int ma_saisie (char chaine[]) {

est équivalente à celle‐ci :

 
Sélectionnez
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 :

 
Sélectionnez
#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>.

 
Sélectionnez
#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 :

 
Sélectionnez
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>.

 
Sélectionnez
#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 :

 
Sélectionnez
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.

 
Sélectionnez
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.

Dans cet exemple, la fonction va convertir l'entier i en chaîne de caractères et la stocker dans la variable s. À l'arrivée, s contiendra « 15 ».
 
Sélectionnez
char s[200];
int i=15;
int code;
code=sprintf(s,"%d",i);
La fonction sscanf fait le contraire.
 
Sélectionnez
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 :

 
Sélectionnez
<type> <nom du tableau> [<taille dimension 1>] [<taille dimension 2>] ;
Par exemple :
 
Sélectionnez
int table[5][5]; /* représente un tableau d'entiers de 5 lignes et 5  colonnes.*/

Ou bien :
 
Sélectionnez
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 :

 
Sélectionnez
#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 :

 
Sélectionnez
#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;
}
Nous aurions pu écrire ce programme sous la forme suivante :
 
Sélectionnez
#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.

 
Sélectionnez
#include <stdio.h> 
#define LIGNES 5;
#define COLONNES 10;

En effet, les rechercher‐remplacer aboutiraient au programme suivant qui ne se compilerait pas :

 
Sélectionnez
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

Image non disponible Corrigé de l'exercice n°9.1 — Affichez une chaine de caractères

 
Sélectionnez
#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 :

 
Sélectionnez
#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;
}

précédentsommairesuivant

  

Licence Creative Commons
Le contenu de cet article est rédigé par Eric Berthomier et Daniel Schang et est mis à disposition selon les termes de la Licence Creative Commons Attribution 3.0 non transposé.
Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright © 2013 Developpez.com.