précédent  index  suivant

14. Fonctions de la bibliothèque


14.1 Comment convertir un nombre en une chaîne de caractères ?

Il suffit d'utiliser sprintf().

	char sz[4];
	sprintf(sz, "%d", 123);
		

Pour convertir un double ou un long, il faut utiliser %f ou %ld.

Le problème de sprintf() est qu'il faut réserver assez de place pour la chaîne résultat. Ainsi le code

	char sz[6];
	sprintf(sz, "%u", i);
		

marchera sur des machines où i est un entier 16 bits, mais il plantera si i est un entier plus grand (> 99999).

En C99, la fonction snprintf permet d'éviter les débordements :

	char sz[4];
	n = snprintf(sz, sizeof sz, "%d", 123);
	if (n < 0 || n >= sizeof sz)
		erreur();
		

14.2 Comment convertir une chaîne en un nombre ?

Si le nombre espéré est un entier, il faut utiliser la fonction strtol(). Elle convertit une chaîne en un entier long, dans une base donnée.

Si le nombre est un réel (float ou double), alors la fonction strtod() fera très bien l'affaire.

	char test[] = "  -123.45e+2";
	char * err = NULL;

	errno = 0;
	double result = strtod(test, &err);

	if (err == test) {
		printf("Erreur de conversion :\n");
	} else {
		if (errno == ERANGE) {
			printf("Depassement :\n");
		} else {
			printf("Conversion reussie :\n");
			if (*err == '\0') {
				printf("Pour toute la chaine\n");
			}
		}
	}
		

Si le nombre est un long double (C99 seulement) alors la fonction strtold() est à préférer.

14.3 Comment découper une chaîne ?

La fonction strtok() est faite pour ça !

	char sz1[] = "this is,an   example ; ";
	char sz2[] = ",; ";
	char *p;

	p = strtok(sz1, sz2);
	if (p != NULL) {
		puts(p);
		while ((p = strtok(NULL, sz2)) != NULL) {
			puts(p);
		}
	}
		

Attention, la fonction strtok() souffre au moins des problèmes / caractéristiques suivants :

Dans des cas simples, on pourra utiliser la fonction strchr().

14.4 Pourquoi ne jamais faire fflush(stdin) ?

La fonction fflush() a un comportement défini uniquement sur les flux ouverts en écriture tels que stdout. Il est possible que sur votre système, appliquer cette fonction à stdin soit possible, mais c'est alors une extension non standard. Le comportement est indéterminé, et imprévisible.

Il faut bien comprendre que stdin n'est pas forcément relié au clavier, mais peut être rattaché à un réseau, un fichier, etc.

14.5 Comment vider le buffer associé à stdin ?

Une bonne manière est de lire sur le flux tant qu'il n'est pas vide, avec les fonctions habituelles comme fgets() ou getchar(). Voici un exemple avec cette dernière :

	c = getchar();
	if (c != '\n')
		while ((getchar()) !=  '\n') {
		};
		

Ce morceau de code permet de lire un caractère, et vide ce qui peut rester dans le buffer, notamment le '\n' final.

14.6 Pourquoi mon printf() ne s'affiche pas ?

Le flux standard stdout, sur lequel écrit printf() est bufferisé. C'est à dire que les caractères sont écrits dans un tampon (une zone mémoire). Lorque celui-ci est plein, ou lorsqu'une demande explicite est faite, il est vidé dans le flux proprement dit (sur l'écran généralement). Tant que le buffer n'est pas vidé, rien ne s'affiche.

Pour vider le buffer, il y a trois possibilités :

14.7 Comment obtenir l'heure courante et la date ?

Il faut simplement utiliser les fonctions time(), ctime() et/ou localtime(), qui contrairement à leurs noms donnent l'heure et la date.

Voici un petit exemple :

	#include <stdio.h>
	#include <time.h>

	int main(void)
	{
		time_t now;
		time(&now);

		printf("Il est %.24s.\n", ctime(&now));

		return 0;
	}
		

14.8 Comment faire la différence entre deux dates ?

Il faut simplement utiliser la fonction difftime(). Cette fonction prend deux time_t en paramètres et renvoie un double.

14.9 Comment construire un générateur de nombres aléatoires ?

Ce n'est pas possible. La bibliothèque standard inclut un générateur pseudo-aléatoire, la fonction rand(). Toutefois, l'implémentation dépend du système, et celle-ci n'est généralement pas très bonne (en terme de résultats statistiques). Si rand() ne vous suffit pas (simulation numérique ou cryptologie), il vous faudra regarder du coté de bibliothèques mathématiques, dont de nombreuses se trouvent sur Internet. En particulier, on consultera les paragraphes 7-0 et 7-1 des Numerical Recipes in C (cf. 4.5) et le volume 2 de TAoCP (cf. 3.9).

14.10 Comment obtenir un nombre pseudo-aléatoire dans un intervalle ?

La méthode la plus simple à faire,

	rand() % N
		

qui renvoie un nombre entre 0 et N-1 est aussi la moins bonne. En effet, les bits de poids faibles ont une distribution très peu aléatoire. Par exemple, le bit de poids le plus faible a une distribution qui peut être celle-ci sur un mauvais générateur : 0 1 0 1 0 1 0 1 0 1 ...

Voici la méthode préconisée dans Numerical Recipes (cf.4.5) :

	(int)((double)rand() / ((double)RAND_MAX + 1) * N)
		

RAND_MAX est défini dans stdlib.h, et N doit être plus petit que RAND_MAX.

14.11 À chaque lancement de mon programme, les nombres pseudo-aléatoires sont toujours les mêmes ?

C'est normal, et c'est fait exprès. Pour contrer cela, il faut utiliser une graine pour le générateur qui change à chaque lancement du programme. C'est la fonction srand() qui s'en charge.

On peut utiliser l'heure système, avec time(), de la facon suivante :

	srand(time(NULL));
		

Notez qu'il est peu utile d'appeler la fonction srand() plus d'une fois par programme.

14.12 Comment savoir si un fichier existe ?

En C ISO, le seul moyen de savoir si un fichier existe, c'est d'essayer de l'ouvrir.

	{
	   FILE *fp = fopen ("fichier.txt", "r");

	   if (fp == NULL) {
		  fputs("Le fichier n'existe pas,\n"
				 "ou vous n'avez pas les droits necessaires\n"
				 "ou il est inaccessible en ce moment\n"
				 , stderr);
	   } else {
		  /* ... operation sur le fichier */

		  fclose(fp);
	   }
	}
		

Dans la norme POSIX, il existe la fonction access(), mais certains systèmes n'implémentent pas cette interface.

14.13 Comment connaître la taille d'un fichier ?

Malheureusement, les fonctions stat() et fstat() de la norme POSIX ne sont pas reprises dans la norme ISO. La seule solution standard est d'utiliser fseek() et ftell(). Toutefois, cela ne marche pas pour les très gros fichiers (supérieurs à LONG_MAX).

14.14 Comment lire un fichier binaire proprement ?

Il faut ouvrir le fichier en mode « binaire », en passant la chaîne "rb" en mode d'ouverture à la fonction fopen(). Cela évite les transformations inopportunes et les problèmes des caractères de contrôle.

De même, pour écrire dans un fichier binaire, on utilise le mode "wb".

14.15 Comment marquer une pause dans un programme ?

Il n'y a pas de fonction standard pour cela. Il existe toutefois la fonction sleep() en POSIX, elle provoque une attente passive pour une durée donnée en secondes.

14.16 Comment trier un tableau de chaînes ?

La fonction qsort() est une bonne fonction de tri, qui implémente le Quick Sort. Le plus simple est de donner un exemple :

	/* Fonction qui compare deux pointeurs
	   vers des chaines pour qsort */
	int pstrcmp(const void * p1, const void * p2)
	{
		return strcmp(*(char * const *)p1, *(char * const *)p2);
	}
		

Les paramètres doivent être des pointeurs génériques pour qsort(). p1 et p2 sont des pointeurs sur des chaînes. Un tableau de chaînes doit être pris au sens d'un tableau de pointeurs vers des char *.

L'appel à qsort() ressemble alors à :

	qsort(tab, sizeof tab, sizeof *tab, pstrcmp);
		

14.17 Pourquoi j'ai des erreurs sur les fonctions de la bibliothèque, alors que j'ai bien inclus les entêtes ?

Les en-têtes (les .h) ne contiennent que les prototypes des fonctions. Le code proprement-dit de ces fonctions se trouve dans des fichiers objets. Ce code doit être « lié » au tien. Cela est fait par un éditeur de liens.

Pour certaines fonctions, il faut spécifier explicitement à l'éditeur de liens où il peut les trouver (et ce particulièrement pour les fonctions non-standard).

Par exemple, sous Unix, pour utiliser les fonctions mathématiques, il faut généralement lier le programme avec la bibliothèque adéquate :

	cc -lm monfic.o -o monprog
		

précédent  index  suivant