2016-08-14 1 views
2

J'ai la chaîne de format et je l'analyse que remplaçant des spécificateurs de format avec des arguments d'entrée. Maintenant, je considère comment allouer de la mémoire pour une telle chaîne de résultats après la substitution des arguments. Je pourrais allouer cette chaîne aussi longtemps que la chaîne de format, mais que la substitution d'une autre chaîne à la place de %s de tout long devra réattribuer cette chaîne dans une fusion indéterministe, ce qui rend nécessaire de faire des calculs inélégants dans le code. Je pensais que je pouvais attribuer cette chaîne créée à partir de chaîne de format juste omble chevalier par char, réaffectant chaque fois comme:La réallocation fréquente de la mémoire pour chaîne est-elle une bonne pratique?

/*** for loop traversing next chars in format string ***/ 
// if new char 
str = realloc(str, sizeof(*str) +1); 
// if %s 
str = realloc(str, sizeof(*str) + strlen(in_str)); 
// if %d 
str = realloc(str, sizeof(*str) + strlen(d_str)); 
+6

Ces instructions semblent incorrectes: 'sizeof (* str)' n'est pas ** la taille de la chaîne allouée jusqu'à présent. – chqrlie

+0

Vous pouvez créer une classe String légère (pour C, une 'struct') qui contient un courant' max_length' (qui devrait initialement être "assez gros pour la plupart des cas"). Cela ajouterait à peu près la même surcharge, car vous devrez toujours vérifier la longueur maximale * avant de l'ajouter. – usr2564301

+4

le motif 'str = realloc (str,' ne permet pas la récupération de mémoire insuffisante –

Répondre

5

Habituellement code bibliothèque interne qui traite de la longueur des chaînes transformables/tableau/listes/whatever autre ne Si vous avez 4 octets de mémoire et que vous avez besoin d'allouer 5, cela alloue réellement 8. Cela réduira le nombre d'appels à realloc(), ce qui est coûteux, pour les opérations ~ log (n). Cependant, il pourrait y avoir d'autres optimisations, en fonction de la bibliothèque.

1

code comme ceci:

str = realloc(str, sizeof(*str) +1); 

est mauvais. Si realloc échoue, il retournera NULL mais il ne sera pas free(str). En d'autres termes - fuite de mémoire. Vous devez affecter le résultat de realloc à un autre pointeur, puis vérifier NULL et agir en conséquence.

Que ce soit bon ou mauvais pratique d'utiliser beaucoup realloc dépend de ce que vous essayez d'obtenir, à savoir la performance, la maintenabilité, la clarté, etc. Le meilleur conseil est: Écrivez le code comme vous le souhaitez. Puis le profiler. Les problèmes de performance? Non -> Soyez heureux. Oui -> Réécrivez le code en mettant l'accent sur les performances.

+2

* ... 'str = realloc (str, sizeof (* str) +1);' est mauvais. * Il est seulement mauvais si le code fait une tentative de récupération à partir d'une allocation échouée. Si la réponse à une allocation échouée est 'exit()' le processus, le la fuite est sans importance. –

+0

@AndrewHenle En plus du commentaire d'Andrew, si le code tombe en panne à cause du pointeur nul, probablement le cas, la fuite est également non pertinente. – Kaz

+0

@Kaz - Ce n'est pas garanti. Sur la plupart des systèmes modernes, tout ira bien, mais comme une pièce générale de code-c, c'est mauvais. Voir: http://stackoverflow.com/questions/2213627/when-you-exit-ac-application-is-the-malloc-ed-memory-automatically-freed – 4386427

2

Je ne commenterai pas les problèmes avec le code qui sont correctement traités dans d'autres réponses.

Appeler realloc pour chaque acte individuel d'extension de la chaîne n'est pas nécessairement une mauvaise pratique. Il semble comme si elle pourrait mal fonctionner, et pour résoudre ce problème, vous pouvez implémenter un système qui augmente la chaîne par incréments plus importants, moins fréquemment. Cependant, comment savez-vous que realloc ne fait pas déjà quelque chose de ce genre en interne? Par exemple, vous pourriez penser que vous êtes intelligent en faisant passer une chaîne de 128 octets à 256 octets, puis à 512, plutôt qu'un caractère à la fois. Mais si ceux-ci sont les seules tailles de bloc internes disponibles, alors realloc ne peut pas aider mais passer par les mêmes tailles. Bon, qu'en est-il de l'économie du nombre brut d'appels realloc effectués? Mais ceux-ci sont juste remplacés par des invocations de la logique de culture de chaîne plus intelligente. Si les performances de cette boucle de création de chaîne de format sont importantes, il convient de les profiler. Faire une version qui réduit les opérations realloc et le profil aussi. Comparez-le sur toutes les plates-formes cibles pour lesquelles vous écrivez et sur lesquelles les performances sont importantes.

Si les performances ne sont pas critiques, optimisez pour des propriétés telles que la bonne structure, la maintenabilité et la réutilisation du code. Une fonction qui construit une chaîne de format n'a pas besoin de connaître la gestion de la mémoire de chaîne. Il a besoin d'une interface abstraite pour travailler avec des chaînes dynamiques. Cette interface peut fournir une fonction intéressante pour changer une chaîne en place en ajoutant une copie d'une autre chaîne à sa queue. Les fonctions autres que le producteur de chaîne de format peuvent utiliser ces opérations de chaîne.Le code de gestion de chaîne peut décider, en un seul endroit, s'il appelle realloc chaque fois que la longueur d'une chaîne change, ou si elle suit la taille de stockage séparément de la longueur, et réduit par conséquent le nombre d'appels realloc.