Chaînes de caractères

Un texte est formé de plusieurs caractères, donc la place nécessaire en mémoire dépend de la longueur du texte. C'est la raison pour laquelle aucun type primitif ne peut suffire à stocker une chaîne de caractère. Par contre, un tableau de caractères peut, avec la bonne capacité, accueillir n'importe quel texte.

Pour que les fonctions qui manipulent des chaînes puissent les parcourir aisément, on place après le dernier caractère une valeur spéciale : le caractère de fin de chaîne. Ce caractère, de code ASCII 0, est noté simplement '\0'. Il faut impérativement penser à l'inclure quand on choisit la capacité du tableau !

int main(void) {
  char tab[6] = {'h', 'e', 'l', 'l', 'o', '\0'};
 
  printf("%s\n", tab);
  return EXIT_SUCCESS;
}
Les chaînes de caractères sont la seule sorte de tableau qui possède des constantes littérales. On peut d'ailleurs les utiliser pour faciliter l'initialisation :
int main(void) {
  char tab[6] = "hello"; /* 5 caractères, mais 6 cases ! */
 
  printf("%s\n", tab);
  return EXIT_SUCCESS;
}
Remarque Cette notation est très pratique, mais attention à ne pas confondre ces deux situations :

int main(void) {
  char p[6] = "hello"; /* p pointe vers une zone modifiable */
  char* q = "hello";   /* q pointe vers une zone constante  */
 
  p[3] = 'i';          /* change le deuxième l en un i       */
  q[3] = 'i';          /* erreur !!!                         */
 
  printf("%s\n", p);
  printf("%s\n", q);
  return EXIT_SUCCESS;
}

Avec printf, on peut envoyer une chaîne sur la sortie standard en donnant le format %s.

printf("%s", "bonjour");
L'affichage d'une chaîne de caractères est très simple, puisque la console attend déjà une suite de caractères. Il n'y a donc aucune transformation à appliquer. Il existe d'ailleurs une autre fonction dans stdio.h qui est spécialisée dans l'affichage de chaînes :

puts("bonjour");
Contrairement à printf, cette fonction revient automatiquement à la ligne après avoir affiché la chaîne.

Cela dit, printf est capable de plus de souplesse dans l'affichage grâce aux indicateurs de format :

  • le premier indique le nombre minimum de caractères à afficher (on complète avec des espaces)
  • le second indique le nombre maximum de caractères à extraire de la chaîne.
printf("%8.4s", "bonjour");
affiche
    bonj

Avec scanf, on peut capturer un mot sur l'entrée standard en donnant le format %s. Il faut faire attention à ne pas placer dans la chaîne plus de caractères qu'elle n'en peut contenir.

int main(void) {
  char tab[20];
 
  printf("%s", "Quel est votre nom ? ");
  scanf("%19s", tab);
 
  printf("%s", "Bonjour, ");
  printf("%s\n", tab);
  return EXIT_SUCCESS;
}
L'indicateur de format 19 signifie qu'il ne faut pas lire plus de 19 caractères (on laisse une case de libre à la fin pour le caractère de fin de chaîne). En réalité, on va probablement en lire bien moins, car on veut obtenir un seul mot, et scanf va s'arrêter dès qu'il atteint un caractère blanc (espace, tabulation ou saut de ligne).

Remarque Pour une fois, il n'est pas nécessaire de recourir à l'opérateur & dans l'appel à scanf puisque tab contient déjà l'adresse où scanf doit écrire les données lues.

Il existe un pendant à puts nommé gets, mais cette fonction ne permet pas d'éviter les débordements de capacité et nous ne nous en servirons donc pas.

Néanmoins, une fonction similaire, fgets, nous offre une possibilité intéressante : elle ne s'arrête pas aux espaces ou aux tabulations, et lit donc une ligne entière de texte en une fois (si la capacité du tableau le permet).

int main(void) {
  char tab[20];
 
  printf("%s", "Quel est votre nom ? ");
  fgets(tab, 20, stdin);
 
  printf("%s", "Bonjour, ");
  printf("%s\n", tab);
  return EXIT_SUCCESS;
}
Remarque Notez l'usage de la constante stdin définie dans stdio.h, qui indique que la lecture se produit sur l'entrée standard. Cette fonction est en effet capable de lire dans toutes sortes de flux, et nous reviendrons dessus quand nous parlerons d'accès aux fichiers.

La bibliothèque standard propose un grand nombre de fonctions dédiées à la manipulation de chaînes, dont les définitions sont regroupées dans l'en-tête string.h.

strlen
prend une chaîne en argument, renvoie le nombre de caractères qui la composent (sans le '\0').
strcpy
prend deux chaînes en arguments et copie le contenu de la deuxième dans la première à la place du contenu existant. Attention à la capacité !
strcat
prend deux chaînes en arguments et copie le contenu de la deuxième dans la première à la suite du contenu existant. Attention à la capacité !
strcmp
prend deux chaînes en arguments et renvoie un entier. Celui-ci est nul si les deux chaînes ont un contenu identique, positif si la première chaîne est avant la deuxième dans l'ordre lexicographique, et négatif sinon.

Remarque Les fonctions strcpy et strcmp permettent de compenser le fait qu'on ne peut pas copier ou comparer des chaînes avec les opérateurs habituels.

Les programmes écrits en langage C peuvent prendre des arguments lorsqu'on les exécute, comme tous les autres programmes que vous avez rencontrés. Pour cela, il faut utiliser la version complète de la première ligne de la fonction principale :

int main(int argc, char** argv) {
  if (argc > 1) {
    puts(argv[1]);
  } else {
    puts("aucun argument !");
  }
  return EXIT_SUCCESS;
}

La variable argc (arguments count) reçoit automatiquement le nombre de mots employés sur la ligne de commande qui a lancé le programme, tandis que la variable argv (arguments values) permet d'obtenir le texte de chaque mot.

Par exemple la commande

$ a.out 12 + 27
donne accès aux données suivantes :

Les arguments de la ligne de commande sont des chaînes de caractères même si ils pourraient être interprétés comme des valeurs numériques. Pour forcer cette interprétation, quelques fonctions sont à notre disposition :

strtol
prend une chaîne de caractères en argument, renvoie la valeur correspondante sous forme d'un long.
strtoul
prend une chaîne de caractères en argument, renvoie la valeur correspondante sous forme d'un unsigned long.
strtod
prend une chaîne de caractères en argument, renvoie la valeur correspondante sous forme d'un double.

On peut utiliser ces fonctions de façon simplifiée si on choisit de ne pas tester si la conversion est réussie.

int main(int argc, char** argv) {
  char txt[50];
  long entier;
  ...
  entier = strtol(txt, NULL, 10);
  printf("%lo\n", entier);
  return EXIT_SUCCESS;
}

Mais la version complète permet de gérer les éventuelles erreurs.

int main(int argc, char** argv) {
  char txt[50];
  char* position;
  unsigned long entier;
  ...
  entier = strtoul(txt, &position, 10);
  if ((entier == 0) && (position==txt)) {
    puts("Ce texte n'est pas un entier naturel !");
    return EXIT_FAILURE;
  } else if (*position != '\0') {
    puts("Conversion partielle !");
  }
  printf("%lo\n", entier);
  return EXIT_SUCCESS;
}

  1. Lecture. Écrivez un programme qui demande à l'utilisateur de taper un mot de passe (ne faisant pas plus de 26 caractères) et indique ensuite si l'authentification a réussi.

    Vous ne devrez pour cela utiliser ni scanf ni fgets.

  2. Statistiques. Écrivez un programme qui lit une ligne de texte (ne dépassant pas 200 caractères) et la stocke dans une chaîne de caractères, puis affiche :

    • le nombre de 'e' qu'elle contient,
    • le nombre de caractères différents qu'elle contient.

  3. Initiales. Écrivez un programme qui affiche la première lettre de chacun de ses arguments.

  4. Multiplication. Écrivez un programme qui affiche le produit de ses deux premiers arguments (on suppose que ce sont des entiers).

    Que donne le programme quand un des arguments n'est pas un entier ? Quand un des arguments est manquant ? Pouvez-vous améliorer le programme pour qu'il gère ces situations ?

  5. Miroir. Écrivez un programme qui affiche sa propre ligne de commande, mais en inversant l'ordre des caractères :

    bob@box:~$ ./a.out toto 456
    654 otot tuo.a/.
    

  6. Truandage. Qu'affiche le programme suivant ?

    int main(void) {
      long int n = 32217268732456802L;
      printf("%s\n", &n);
      return EXIT_SUCCESS;
    }

    Comment faire pour calculer la valeur qu'il faudrait donner à n pour qu'il affiche bonsoir ? Commencez par afficher n en hexadécimal. Voyez-vous les lettres ?

retour à la page d'accueil

retour au sommet