Bonjour tout le monde,

Tout à coup j'ai eu une subite envie de faire une petite fonction permettant de lire une chaînes de caractères de taille variable sur stdin (et plus généralement, sur un FILE *).
Le comportement de la fonction est le suivant :
- La fonction prend un paramètre, le flux (FILE *) sur lequel la chaîne de caractères sera lue
- La fonction retournera un char *, l'adresse du premier caractère lu ou NULL si une erreur survient
- Si une erreur survient, le flux sera consommé (= lecture des caractères juqu'à ce qu'on tombe sur \n ou EOF)
La signature de la fonction sera donc la suivante : char * get_line(FILE *);

N'ayant pas trouvé grand chose sur la lecture de chaînes de caractères de taille variable, j'ai du faire chauffer mes méninges et trouver un algorithme, espèrons qu'il soit potable.
Ne sachant pas trop comment écrire cela en pseudo-code, je vais le faire avec de bonnes vieilles phrases.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
/*
D'abord on va allouer un espace mémoire de taille arbitraire (32 octets) pouvant stocker des char.
Si l'allocation a réussie, on va pouvoir lire le flux caractère par caractère.
    Tant qu'on ne rencontre pas \n ou EOF :
         Si l'espace alloué n'est pas suffisant, on va augmenter la taille de l'espace précédemment alloué (+ 32 octets).
         Si l'allocation a échouée, on va libérer l'espace précédemment alloué, consommer le flux et sortir de la boucle.
S'il n'y a pas eu d'erreur d'allocation, on rajoute le \0 à la chaîne de caractères.
On retourne un pointeur sur le premier élément de l'espace alloué ou NULL s'il y a eu une erreur d'allocation.
*/
Première question, est-ce que cet algorithme semble correct, potable ?
Pour la réallocation, j'ai vu certains codes qui doublaient la taille de l'espace alloué au lieu de l'agrandir d'un nombre fixe d'octets. Y a-t-il une méthode préférable à l'autre, ou est-ce dépendant de la situation ? Et si c'est dépendant de la situation, quelle méthode répondrait le mieux à la problématique actuelle ?

Passons maintenant à l'implémentation en C :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
/* /Document/C/str/mstr.h */
#ifndef MSTR_H_INCLUDED
#define MSTR_H_INCLUDED
 
#include <stdlib.h>
#include <stdio.h>
 
#define MSTR_ALLOC_BLOCK_SIZE 32
 
char * get_line(FILE *);
 
#endif /* MSTR_H_INCLUDED */
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/* /Document/C/str/mstr.c */
#include "mstr.h"
 
char * get_line(FILE * stream) {
    /* Allocation du bloc de depart */
    size_t size = MSTR_ALLOC_BLOCK_SIZE;
    char * s = malloc(size);
 
    /* Si l'allocation a reussie */
    if(s != NULL) {
        size_t i;
        int c;
 
        /* On lit tous les caractères jusqu'a \n ou EOF */
        for(i = 0; (c = fgetc(stream)) != '\n' && c != EOF; i++) {
            /* Si l'espace alloue n'est plus suffisant
               on essaie de l'agrandir */
            if(i >= size) {
                char * tmp = realloc(s, size += MSTR_ALLOC_BLOCK_SIZE);
 
                /* Si l'allocation a reussie, on recupere le pointeur
                   Sinon on libere l'espace precedemment alloue,
                   on vide le buffer du flux et on sort du while */
                if(tmp != NULL) {
                    s = tmp;
                }
                else {
                    free(s);
                    s = NULL;
                    while((c = fgetc(stream)) != '\n' && c != EOF) {
                    }
                    break;
                }
            }
            s[i] = (char)c;
        }
        /* On ajoute le \0 terminal a la chaine recuperee */
        if(s != NULL) {
            s[i] = '\0';
        }
    }
 
    return s;
}
Qu'en pensez-vous ?
Le code semble fonctionner. Semble car j'avoue avoir un peu de mal pour les tests unitaires.. Est-il possible de faire échouer volontairement un malloc/realloc ?

Dernière petite chose, j'ai eu beau lutter, un warning persiste à la compilation.. J'utilise code::block avec les options de compilations suivantes (GNU/CSS compiler) : -Wall -Wextra -ansi -O -Wwrite-strings -Wstrict-prototypes -Wuninitialized -Wunreachable-code


Et voici le warning en question :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
/*
\Documents\C\str\mstr.c||In function `get_line':|
\Documents\C\str\mstr.c|10|warning: will never be executed|
||=== Build finished: 0 errors, 1 warnings ===|
*/
J'ai demandé à une connaissance de compiler, il a utilisé le même compilateur (mais je ne sais pas si c'est la même version par contre) avec les mêmes options, et point de warning chez lui.

Merci d'avoir pris le temps de me lire et merci d'avance pour vos futures réponses. =)

Cordialement, Krystal_.