Parser une saisie en C avec la fonction strtok

Si vous récupérez une saisie de l’utilisateur et que vous souhaitez l’analyser selon une syntaxe particulière pour en retirer des arguments c’est que vous voulez parser la saisie.

Une solution simple et portable en C est la fonction strtok de string.h . Par exemple si à partir de la chaine char str = “fonction argument1 argument2” vous voulez obtenir un char **argv = {“fonction”, “argument1”, argument2"} c’est une bonne idée d’utiliser la fonction strtok.

On pourrait croire qu’il y a plus simple, juste en utilisant quelques pointeurs, mais imaginez un peu que l’utilisateur s’amuse a mettre des espaces n’importe comment par exemple " fonction argument1 argument2 " …

Donc voici un code qui permet d’allouer juste comme il faut votre char **argv :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_ARG 10
#define SIZE 256
int main(void)
{
char **argv = NULL;
char *saisie = malloc(sizeof(char) * SIZE);
char *p = NULL;
size_t i = 0;
char c;
/* On recupère la saisie */
printf(">");
fgets(saisie, SIZE, stdin);
/* On supprime le de la fin */
if(NULL != (p = strrchr(saisie, ' ')))
*p = '\0';
else
while(' ' != (c = fgetc(stdin)) && c != EOF);
/* On alloue argv */
argv = malloc(sizeof(char *) * MAX_ARG);
/* 
* On lance le premier strtok
* char *strtok(char *ptr, char *str);
* ptr doit être la saisie qu'on veut parser
* et str est une chaine qui contient les caractères
* sur lesquels on va couper la saisie. Vous pouvez
* bien sûr en mettre plusieurs
*/
p = strtok(saisie, " ");
while(p != NULL)
{
/* 
* Ici p est un pointeur sur une chaine
* qui contient exactement l'argument i
*/
if(i < MAX_ARG)
{
argv[i] = malloc(sizeof(char) * (1+strlen(p)));
strcpy(argv[i], p);
i++;
}
else
break;
/* 
* On lance un nouvel appel a strtok
* par contre on lui donne en argument NULL
* pour qu'il sache que c'est celle du dernier
* appel, on peut aussi changer les caractères
* pour parser...
*/
p = strtok(NULL, " ");
}
argv[i] = NULL;
/* On affiche les resultats */
for(i = 0; argv[i] != NULL; i++)
{
printf("arg[%d] = '%s' ", i, argv[i]);
free(argv[i]);
}
free(argv);
free(saisie);
return 0;
}

Attention : la chaine saisie a été modifiée par strtok, elle ne doit pas avoir l’attribut const pour ça. D’ailleurs si vous envoyez une chaine constante à strtok ça fait un segfault…

Bon, le seul problème avec cette technique c’est que strtok ne nous dit pas sur quel caractère il a coupé la chaine. Mais ça reste un moyen rapide d’arriver à faire quelque chose de propre…

Bons codes :-)

EDIT : Il manquait quelques free…