# Chaines de caractères (et tableaux)

En C il n'y a pas de type String, les chaines de caractères sont
simplement des tableaux de caractères. Sauf que puis ce que l'on ne sait
pas combien de la longueur du tableau a été replis, donc on met un
caractère de fin de chaine à la fin du tableau `\0`.

``` c
char ma_chaine[21] = "Hello World!\n";
```

[![2023-09-29_08-38-33_screenshot.png](https://books.snowcode.ovh/uploads/images/gallery/2023-10/scaled-1680-/2023-09-29-08-38-33-screenshot.png)](https://books.snowcode.ovh/uploads/images/gallery/2023-10/2023-09-29-08-38-33-screenshot.png)

Il est très important de toujours vérifier l'input des utilisateur·ice·s
car si la personne entre quelque chose de plus long que la taille du
tableau cela peut être une faille de vulnérabilité (car cela peut mener
à un BufferOverflow). C'est notament arrivé au programme `sudo` sous
linux. Si vous voulez en apprendre plus vous pouvez regarder [cette
vidéo](https://www.youtube.com/watch?v=TLa2VqcGGEQ).

#### Lecture des chaines de caractères

Il existe par exemple `gets()`, `scanf()` ou encore `fgets()` pour
prendre un input de l'utilisateur·ice.

Cependant il ne faut **pas** utiliser `gets()` car il ne vérifie pas la
taille des données (ce qui peut donc mener à un BufferOverflow). Il faut
donc toujours utiliser `scanf` ou `getf`.

##### scanf

Voici par exemple comment récupérer les max 20 premiers caractères d'un
input (le reste sera ignoré).

``` c
scanf("%20[^\n]%*c", ma_chaine);
```

Pour déconstruire un peu ce qu'il se passe ici :

- `%20` signifique que l'on prends les 20 premiers caractères

- `[^\n]` signifie que l'on arrete de prendre des caractères quand
  l'utilisateur·ice fait ENTER

- `%*c` signifie que l'on ignore le dernier caractère (le retour à la
  ligne `\n`)

  Autre chose intéressante à noter ici, il n'y a pas de `&` devant le
  nom de la fonction contrairement à avant quand on récupérait des
  caractère ou nombres uniques. Cela est dû au fait que `&` sert à
  passer l'addresse d'une variable (le pointeur) et qu'un tableau (comme
  une chaine de caractère) *est* déjà une addresse (pointeur).

##### fgets

`fgets` fonctionne assez différemment de `scanf`, voici comment on peut
faire quelque chose de similaire à l'exemple précédent en utilisant
fgets :

``` c
fgets(ma_chaine, 20, stdin);
```

Attention cependant que fgets compte `\n` comme un caractère et l'inclus
dans le résultat. Donc bien que la syntaxe de fgets soit plus simple, il
faut mieux utiliser `scanf` car elle s'occupe du caractère `\n` toute
seule.

#### Affichage des chaines de caractères

##### puts

L'exemple suivant va afficher la chaine de caractère en y ajoutant un
retour à la ligne automatiquement à la fin (c'est tout l'interet du
puts), c'est un peu comme le `System.out.println` en Java :

``` c
puts(ma_chaine);
```

##### fputs

Cet exemple fonctionne de manière similaire du `puts` sauf qu'il
n'ajoute pas de retour à la ligne. C'est un peu comme le
`System.out.print` en Java.

``` c
fputs(ma_chaine, stdout);
```

##### printf

Printf est surtout intéressant pour formatter l'affichage (c'est
l'équivalent du `System.out.printf` en Java).

``` c
printf("%s\n", ma_chaine);
```

#### Autres fonctions

Il existe une librarie `string` en C permettant d'intéragir plus
facilement avec les chaines de caractères. Attention cependant, il ne
faut pas la confondre avec le type String en Java, car en C "string"
n'est pas un type les chaines de caractères sont simplement des tableaux
de `char`

Pour importer la librarie string, il suffit d'ajouter la ligne suivante
au dessus du fichier :

``` c
#include <string.h>
```

Maintenant voici une petite listes des fonctions les plus utiles de
string :

| Fonction                         | Explication                                                                                                                                      |
|----------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
| `strlen(ma_chaine)`              | Compte le nombre de caractères de la chaine jusqu'au `\0`                                                                                        |
| `strncmp(chaine1, chaine2, n)`   | Compare les n premiers caractères des chaines. Si les deux sont les même cela signifie que les deux sont identiques                              |
| `strncpy(dest, source, n)`       | Copie les n premiers caractères de la source vers la destination (le `\0` n'est pas ajouté)                                                      |
| `sprintf(dest, "%d + %d", 4, 5)` | Fait comme `printf` sauf qu'à la place de l'afficher, il le stoque dans une variable. C'est comme le `String.format` en Java                     |
| `sscanf(src, "%d + %d", &a, &b)` | Fait comme le `scanf` sauf qu'a la place de le demander depuis le stdin (standard input), il va le prendre depuis une chaine de caractère source |
| `memset(src, n, 0)`              | Initialise les n premiers caractères de la chaine src avec le caractère mentioné (ici on remplace tout par `\0`)                                 |
| `strchr(chaine, car)`            | Recherche la première occurence d'un caractère dans une chaine et retourn eun pointeur vers celle-ci                                             |
| `strstr(chaine, sous-chaine)`    | Recherche la première occurence d'une sous-chaine donnée dans une chaine et retourne un pointeur vers celle-ci.                                  |

#### Exemple de manipulation de tableau/chaines

``` c
/* Stoquer une chaine dans un tableau */
char ma_chaine[20+1] = "Hello, World!";

/* Accéder au 5e caractère de la chaine */
printf("Le 5e caractère est %c\n", ma_chaine[4]);

/* Modifier un caractère */
ma_chaine[4] = ' ';

/* On peut aussi mettre le \0 n'importe où pour couper une chaine */
ma_chaine[4] = '\0';
printf("La chaine est maintenant : %s\n", ma_chaine);
```