2010-01-21 6 views
1

Je suis un programmeur C++ plutôt inexpérimenté, donc cette question est probablement plutôt basique. Je suis en train d'obtenir le nom de fichier pour mon copule:Concaténation de chaînes en C++

string MonteCarloBasketDistribution::fileName(char c) 
{ 
    char result[100]; 
    sprintf(result, "%c_%s(%s, %s).csv", copula.toString().c_str(), left.toString().c_str(), right.toString().c_str()); 
    return string(result); 
} 

qui est utilisé dans:

MonteCarloBasketDistribution::MonteCarloBasketDistribution(Copula &c, Distribution &l, Distribution &r): copula(c), left(l), right(r) 
{ 
    //..... 
    ofstream funit; 
    funit.open (fileName('u').c_str()); 

    ofstream freal; 
    freal.open (fileName('r').c_str()); 
} 

Cependant, les fichiers créés ont des noms, des ordures composées principalement de personnages étranges. Une idée de ce que je fais mal et comment le réparer?

+2

Qu'est-ce qu'une "copule"? Plus précisément, de quel type s'agit-il? –

+0

Le premier spécificateur de format pour sprintf est cassé. –

+0

@Neil: la copule est de type Copula. : P Voir première ligne du 2ème extrait. –

Répondre

14

sprintf a 4 place détenteurs alors que vous donnez seulement 3 paramètres.

Je suggère:

string MonteCarloBasketDistribution::fileName(char c) { 
    std::ostringstream result; 
    result << c <<"_"<<copula<<'('<<left<<", "<<right<<").csv"; 
    return result.str(); 
} 

Votre sprintf n'est pas sûr pour dépassement de mémoire tampon, utilisez plutôt C99 snprintf ou std::stringstream

+0

Généralement d'accord, sauf que tout ce qu'il présente est basé sur des personnages, les flux sont un peu trop. –

+0

Le point est que 'toString()' en C++ est '' '. Il est faux de fournir des membres 'toString()' - ce n'est pas Java ou C#. Iostreams beaucoup plus flexible. – Artyom

+0

La décision d'utiliser 'sprintf' ou des flux est en grande partie une question de choix. Personnellement, je déteste les cours d'eau. Je trouve 'sprintf' beaucoup plus cohérent et plus facile d'avoir un contrôle total de la sortie. –

5

Vous avez quatre spécificateurs dans votre chaîne de format, mais vous ne fournissez que trois arguments supplémentaires.

3

La seule chose qui semble tout à fait cassé est que vous ne passer 3 paramètres de données à votre sprintf, mais il attend 4 (% c,% s,% s,% s)

+0

Le premier spécificateur de format pour sprintf est cassé. –

13

Puisque toutes les choses que vous punaiser ensemble sont basées sur des caractères, en utilisant sprintf pour c'est un peu bête.

Quel programmeur C++ devrait faire il y a quelque chose de plus le long des lignes de:

std::string result = copula.toString() + "(" + left.toString() + "," 
        + right.toString() + ")"; 
+0

Avec la mise en garde qu'il existe des situations dans lesquelles l'utilisation d'un ostringstream est une bien meilleure idée. Dans ce cas, ce code est probablement la bonne chose. – Omnifarious

+0

"Devrait" est terriblement subjective et une question de style. –

+0

Il est parfois utile d'avoir un spécificateur de format séparé et clair, même lorsque vous ne traitez que des chaînes. Je trouve que de longues séquences encombrées de concaténations de cordes sont douloureuses pour les yeux. Avec quelque chose comme "% c_% s (% s,% s) .csv" vous pouvez immédiatement visualiser la règle de formatage. En utilisant Boost.Format, vous bénéficiez des spécificateurs de format sans les dangers de paramètres manquants/invalides. –

4

Puisque vous semblent travailler sur std :: string, vous ne devez pas utiliser sprintf du tout. std :: string a simple à utiliser des opérateurs surchargés, donc vous pouvez concaténer les chaînes en utilisant + =. Je pense que + fonctionne aussi, donc juste "ajouter" des chaînes std :: ensemble.

2

En supposant que toString() retourne un std::string,

Ce:

sprintf (résultat, "% s c_% (% s,% s) .csv", copula.toString(). c_str(), left.toString(). c_str(), right.toString(). c_str());

... devrait être:

sprintf (résultat, "% s _% s (% s,% s) .csv", copula.toString(). c_str(), left.toString(). c_str(), right.toString(). c_str());

+0

John, vous avez probablement raison de dire que le% s devrait être le premier au lieu du% c, mais peut-être qu'il voulait juste le premier caractère de la chaîne.Si c'était le cas, il avait toujours tort - il passait l'adresse de la chaîne plutôt que le premier omble. Ce que vous avez vraiment manqué ici ne correspond pas au nombre d'arguments passés dans le sprintf, trois, quand le spécificateur en nécessite quatre. Moins un pour vous, si je pouvais voter. –

3

Boost a un formatting library qui est plus sûr que printf et ses amis.

#include <boost/format.hpp> 
string MonteCarloBasketDistribution::fileName(char c) 
{ 
    return boost::str(boost::format("%c_%s(%s, %s).csv") 
     % c % copula.toString() % left.toString() % right.toString()); 
} 

ou bien:

#include <boost/format.hpp> 
string MonteCarloBasketDistribution::fileName(char c) 
{ 
    return boost::str(boost::format("%1%_%2%(%3%, %4%).csv") 
     % c % copula.toString() % left.toString() % right.toString()); 
} 

Avec ce dernier exemple, Boost sait que% 1% est un caractère et% 2% thru% 4% sont des chaînes par "regarder" les types des arguments transmis via l'opérateur%.

+0

: O Boost me surprend tout le temps. – qba

+0

Chaque fois qu'il semble y avoir une fonctionnalité généralement utile manquante dans le langage ou dans la bibliothèque standard, il est probable qu'elle a été implémentée dans Boost. :-) –

+0

Comment boost gère le premier argument étant un% c et la chose qui lui est passée est l'adresse d'une chaîne, pas un caractère? –