a- Enlève le system("pause")
. 1 c'est limité à windows. 2. exiger la pause ne sert à rien quant on a appris à utiliser son IDE.
De plus, cela n'a rien à faire dans un tuto très ciblé où les gens sont censés déjà avoir pris leur IDE en main.
b- En C99 les #define
sont dépréciés en faveur des const
antes pour stocker des … constantes.
c- Mais … côté politique intelligente, jouer avec l'extra-length va te compliquer le boulot car tu vas devoir jongler entre capacité et longueur de chaîne. En C++, la politique initiale fut de plus ou moins multiplier par 2 à chaque fois. Ceci dit, je suis tombé sur un article très intéressant au sujet de ce qui aurait été le plus efficace: https://github.com/facebook/folly/blob/master/folly/docs/FBVector.md
Mais tout cela c'est de la technique avancé. Il faudrait aussi envisager les SSO (Small String Optimization), ou juste la version du pauvre : la Empty String Optimization). Dans un premier temps, realloc()
fait très bien son boulot, et en interne il va opérer des choses équivalentes vu qu'il ne déplacera la mémoire que si la nouvelle quantité demandée ne rentre plus à l'endroit courant.
d- En C aussi, size_t
existe ( http://ewontfix.com/9/ – très bon blog au demeurant)
e- init()
a pour précondition que le paramètre str
soit non null -> assert est ton ami
f- D'ailleurs, pourquoi allouer buffer
?
g- calloc()
n'apporte pas grand chose. Un buffer->s[0] = 0
suffit amplement, c'est d'ailleurs un des deux invariants de ta chaine: buffer->s[buffer->strlen] == 0
; l'autre est que buffer->strlen <= buffer->capacity
; et tu sembles aussi exiger que capacity
soit non nul.
(Pour calloc
, Faut dire que je suis très peu réceptif à la programmation défensive, pour ne pas dire hostile)
BTW, on notera que l'emploi de calloc
n'est pas cohérent avec celui de realloc
.
h- Ta fonction append
n'est pas const-correcte, il manque le const
.
i- Ton utilisation de realloc
est totalement bugguée (ou une des raisons qui fait que je critique le C: le pays magique où les erreurs n'existent pas). Une utilisation correcte est:
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 | int append_raw(str * rhs_, char const* lhs_) {
// les préconditions
assert(rhs_);
assert(lhs_);
// les invariants -> à mettre dans une fonction car cela servira partout en début en fin
assert(rhs_->buffer);
assert(rhs_->buffer[rhs_->strlen] == 0);
assert(rhs_->strlen <= rhs_->capacity);
const size_t len = strlen(lhs_);
if ( .... ) {
const size_t new_capacity = ...;
// la post-condition du calcul de capacity qui devient le futur invariant
assert(new_capacity >= rhs_->buffer + len);
char * s = realloc(rhs_->buffer, new_capacity+1);
if (s == 0) { return ENOMEM; }
// alloc OK => on commite
rhs_->buffer = s;
rhs_->capacity = new_capacity;
}
// on peut balancer directement memcpy car les tailles
// sont bonnes et on sait d'où on part
memcpy(rhs_->buffer+rhs_->strlen, lhs_, len);
rhs_->strlen += len;
rhs_->buffer[rhs_->strlen] = 0;
// De nouveau les invariants
// et on valide que tout s'est bien passé
return 0;
}
|
NB: J'ai appelé la fonction append_raw
car il manque l'ajout entre deux structures str
, ou l'ajout char const*
+ str*
.
j- erase
et init
ne sont pas équilibrées. Si erase
libère le pointeur reçu, alors init
doit allouer une structure chaine et la renvoyer. Les responsabilités d'allocation et de libération doivent être équilibrées.