# Fonctions de base en langage C/stdlib.h

Le fichier en-tête <stdlib.h> déclare des fonctions qui effectuent la conversion de nombres, la gestion de la mémoire et d'autres tâches.

## Conversion de chaînes en nombres

Certaines fonctions de <stdlib.h> permettent de la conversion de chaînes de caractères en valeurs numériques.

### Les fonctions

* int atoi(const char *CH)
    atoi retourne la valeur numérique représentée par CH comme int
    (depréciée par strtol).
* long atol(const char *CH)
    atol retourne la valeur numérique représentée par CH comme long
    (depréciée par strtol).
* double atof(const char *CH)
    atof retourne la valeur numérique représentée par CH comme double
    (depréciée par strtod).
* long strtol(const char * restrict nptr, char ** restrict endptr, int base)
    strtol retourne la chaine nptr considérées comme étant en base de numération base comme un long. Le reste de la chaine qui n'a pas pu être convertie est pointée par *endptr, positionne errno en cas d'erreur.
* De même strtod convertit une chaîne en double.

### Remarques

* En cas de problème de conversion, les fonctions atoi, atol, atof retournent la valeur 0 sans rien signaler. Par contre, les fonctions strtol et strtod positionnent errno en cas de problème.
* Le programmeur peut aussi utiliser la fonction sscanf pour ce genre de conversion.

### Exemple de conversion d'une chaîne en int

Le programme suivant strtol.c convertit une chaine de caractères en int avec strtol. Le traitement des erreurs de conversions est effectué en détail.

## Gestion de la mémoire
### Principes à respecter

* Tester le pointeur renvoyé par les fonctions d'allocation, si NULL un problème a eu lieu.
* Une taille ou un nombre d'éléments à 0 avec malloc et calloc peuvent donner un pointeur qu’il ne faut pas utiliser.
* Libérer la mémoire allouée dès que possible à l'aide de la fonction free. Ne pas charger ou conserver inutilement des éléments en mémoire.
* Les fonctions d'allocation prennent :
** en priorité la mémoire libérée par les free précédents
** si pas assez de mémoire contigüe disponible au niveau du process → demande au système un morceau de mémoire commune a tous les process par une fonction système de bas niveau (2) comme sbrk.
* free rend la mémoire disponible pour le process en cours, mais peut ne pas la rendre au système.
* Ne pas mélanger les appels aux fonctions d'allocation mémoire de niveau système(2) et celles de niveau utilisateur (3) déclarées dans stdlib.h.
* Pour éviter un morcèlement de la mémoire du process, libérer la mémoire en respectant la règle du "dernier alloué, premier libéré"
* Eviter de morceler la mémoire en allouant et desallouant des zones de mémoire de très petites tailles.
* Si des structures contiennent des pointeurs (Ex.: char *) et qu’elles sont de taille impaire, lors de deux allocations successives ces pointeurs peuvent être a cheval sur une frontière de mot, ce qui entraîne des cycles machines supplémentaires lors de l'accès aux données. C'est pourquoi, il serait souhaitable d’utiliser des fonction d'allocation avec contraintes d'alignement comme valloc à la place de malloc. Attention, ces fonction peuvent ne pas être portables.

### À éviter

Si beaucoup d'allocation de gros objets, effondrement du système par manque de mémoire. Les autres process n'auront plus de mémoire souvent jusqu'à ce que notre process soit terminé, ce qui peut s'éterniser...

### Exemple meilleur

Si possible, allocation et libération successive pour chaque objet.
* L'utilisation de tableau de type VLA Variable Lengh Array introduit par l'ISO C99, peut être une solution.

## Communication avec le système
### Gestion de l'arrêt du programme

La fonction principale main d'un programme prévoit habituellement un point de sortie par une instruction return suivie d'un code retour destiné au système : 0 (EXIT_SUCCESS) si le fonctionnement a été jugé nominal ou une autre valeur qui pourra être considéré par l'environnement d'appel comme un code d'erreur. Cette instruction fait appel à la fonction exit vue plus bas et donc appelle les fonctions de terminaison mises en place par atexit.
Les fonctions :
En plus de l'instruction return, la bibliothèque standard du langage C offre trois fonctions décrites dans l'include stdlib.h pour terminer un programme.
* void abort(void)
    abort termine le processus en cours de façon anormale. Il cause la génération du signal SIGABRT que le programme pourra intercepté dans le seul but de nettoyer son environnement. Le processus se terminera de toute façon. Les flux ouverts sont vidés et fermés.
* void exit(int status)
    exit termine un programme de façon normale et vide et ferme tous les flux encore ouverts. Les fonctions de terminaison empilées par atexit sont exécutées dans l’ordre inverse de leur enregistrement. La fonction exit redonne enfin le contrôle à l'environnement du programme en retournant la valeur status comme code de retour.
* int atexit(void (*function)(void))
    atexit enregistre à chaque appel une fonction de terminaison function à exécuter en sortie de votre programme par exit ou return. La fonction exit ne doit jamais être appelée dans function. Au moins 32 fonctions de terminaison peuvent être empilées.
    Ce mécanisme permet d'exécuter le code de fonctions de terminaison de façon systématique quel que soit le point de sortie emprunté. Il est utile par exemple pour éliminer un verrou placé par votre programme afin de garantir un accès exclusif à un répertoire, pour se déconnecter proprement d'une base de données... Vous devez cependant envisager les situations d'exception où votre programme se termine anormalement : par abort, par le système (signal non pris en compte ou imparable), par un arrêt brutal de l'ordinateur...
Un exemple :

### Exécution d'une commande par system

int system(const char * string);
La fonction system permet de démarrer un processeur de commande fournit par l'environnement hôte et de lui passer une chaîne de caractère string contenant la commande à exécuter. system retourne 0 si tout s'est bien passé.
Exemple d’utilisation :
Le programme contenu dans le source system.c lance le script UNIX bonjour.sh
Le script bash bonjour.sh écrit la chaîne "Bonjour tout le monde !" sur la sortie standard stdout.
Remarques portabilité :
* Il faut tester si un processeur de commande est disponible (voir l'exemple).
* La portabilité de la commande est limitée : le processeur de commande dépend du système hôte, les codes retours dépendent de l'implémentation.
* C'est un moyen coûteux en ressource : pour de nombreuses tâches comme afficher la liste des fichiers d'un répertoire par exemple, il vaut mieux appeler les fonctions systèmes comme stat(2).

### Lecture et écriture dans l'environnement

Il est possible de récupérer la valeur d'une variable de l'environnement hôte avec la fonction getenv :
char *getenv(const char *name);
Le paramètre name est une chaîne de caractère qui représente le nom de la variable à demander à l'environnement hôte. Si la variable demandée existe, un pointeur sur la zone mémoire la contenant est retourné, sinon NULL.
Exemple d’utilisation :
Le programme contenu dans le source getenv.c retourne la valeur d'une variable d'environnement dont le nom lui est passé en paramètre :
Remarques sur l’utilisation de getenv :
* Les variables d'environnement prédéfinies dépendent souvent du système hôte : Windows, Unix, Linux, il faut absolument tester si le retour de getenv est NULL.
* Il est interdit de modifier la chaîne retournée par getenv.
* Il faut sauvegarder dans une autre zone mémoire ou utiliser rapidement la valeur retournée. Un appel ultérieur à getenv modifiera ces valeurs.
* L'utilisation des variables d'environnement est cependant très utile pour assurer la w:traçabilité dans les logiciels (nom de l'utilisateur, du système utilisé, de la machine d'exécution...) dans des fichiers de traces (log) ou sur les sorties (impressions, entête de fichiers de sortie).
Pour positionner une variable accessible dans l'environnement du programme, il existe les fonctions setenv et putenv.

## Algorithmes
### Tri d'un tableau d'éléments

La fonction qsort (quick sort = tri rapide) permet de trier un tableau contenant des données de toutes natures dans un ordre croissant. Elle appelle votre fonction de comparaison compar en lui passant des pointeurs sur deux éléments du tableau.
Votre fonction compar doit déterminer si les deux éléments sont dans le bon ordre. Si vous estimez que :
* le premier est plus petit (inférieur) au deuxième, vous renvoyez une valeur entière négative (inférieure à 0). Cela signifie aussi que les deux éléments sont dans le bon ordre.
* le premier est égal au deuxième, vous renvoyez une valeur entière égale à 0. Ce test d'égalité peut servir pour une utilisation ultérieure de compar avec une fonction de recherche comme bsearch.
* le premier est plus grand (supérieur) au deuxième, vous renvoyez une valeur entière positive (supérieur à 0). Cela signifie aussi que les deux éléments ne sont pas dans le bon ordre.
Exemple :
Résultats :

### Recherche dans un tableau trié

La fonction bsearch (binary search = recherche dichotomique) permet de rechercher si un tableau trie suivant la fonction de comparaison compar contient l'élément *key (selon les critères définis dans la fonction compar).
Exemple basé sur le précédent :
Résultats
L'élément {0, 3} a été trouvé par bsearch qui a renvoyé (3, 3) car la fonction qs_tri de l'exemple ne compare que le champ valeur de la structure ELEMENT.

### Génération de nombres pseudo-aléatoires

Le langage C fournit plusieurs fonctions générant de séries de nombres pseudo-aléatoires. Les séries sont reproductibles à condition de démarrer le générateur à partir de la même graine (seed en anglais).
La fonction rand et son modificateur de graine srand produisent des entiers dans l'intervalle [0;RAND_MAX]. RAND_MAX est une constante de stdlib.h valant au moins 32767.
Fonctionnement :
On appelle éventuellement une fois srand en lui passant la graine, puis les appels successifs de rand retournent les nombres de la série.
Remarques
* On peut choisir une série de façon aléatoire en fournissant comme paramètre à srand le retour de la fonction time de <time.h> : srand((unsigned int)time((time_t *)NULL));.
* Le générateur random et son modificateur de graine srandom sont meilleurs que rand (moins cyclique).

## Fonctions non conformes ANSI-C

Les trois fonctions suivantes sont réservées à DOS: elles ne sont pas conformes au standard ANSI-C et elles ne sont pas portables. Conversion de nombres en chaînes de caractères
* char *itoa (int VAL, char *CH, int B)
    itoa convertit VAL dans une chaîne de caractères terminée par '\0' et attribue le résultat à CH; itoa retourne CH comme résultat. B est la base utilisée pour la conversion de VAL. B doit être compris entre 2 et 36 (inclus). (Réservez assez de mémoire pour la chaîne résultat: itoa peut retourner jusqu'à 17 bytes.)
* char *ltoa (long VAL, char *CH, int B)
    ltoa convertit VAL dans une chaîne de caractères terminée par '\0' et attribue le résultat à CH; ltoa retourne CH comme résultat. B est la base utilisée pour la conversion de VAL. B doit être compris entre 2 et 36 (inclus). (ltoa peut retourner jusqu'à 33 bytes.)
* char *ultoa (unsigned long VAL, char *CH, int B)
ultoa convertit VAL dans une chaîne de caractères terminée par '\0' et attribue le résultat à CH; ultoa retourne CH comme résultat. B est la base utilisée pour la conversion de VAL. B doit être compris entre 2 et 36 (inclus). (ultoa peut retourner jusqu'à 33 bytes.)
| stdio.h | string.h |