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();
    

haut de page

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;
    double result = strtod(test, &err);
    if (err != NULL) {
        if (err == test) {
            /* conversion impossible */
        }
        else {
            /* erreur de conversion */
        }
    }
    

haut de page

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, cette fonction modifie son premier paramètre. Elle utilise une variable globale cachée, elle est donc à utiliser avec précautions.

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

haut de page

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.

haut de page

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.

haut de page

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 :

haut de page

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;
    }
    

haut de page

14.8 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).

haut de page

14.9 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.

haut de page

14.10 À 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.

haut de page

14.11 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.

    if (fopen("fichier.txt", "r") == NULL) {
        fputs("Le fichier n'existe pas,"
              " ou vous n'avez pas les droits necessaires\n", stderr);
    }
    

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

haut de page

14.12 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).

haut de page

14.13 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".

haut de page

14.14 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.

haut de page

14.15 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);
    

haut de page

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

Les fichiers d'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 lier le programme avec la bibliothèque adéquate :

    gcc -lm monfic.o -o monprog
    

haut de page

précédent  index  suivant

faq-fclc 5/3/2002 (8h 59:05)