在C++中连接字符串

问题描述:

我是一个缺乏经验的C++程序员,所以这个问题可能很基本。我想为我的系词获取文件名:在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); 
} 

这是在使用:

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()); 
} 

然而,创建的文件有垃圾的名字,从怪异的人物为主。任何想法我做错了什么,以及如何解决它?

+2

什么是“copula”?具体来说,它是什么类型? – 2010-01-21 21:30:31

+0

sprintf的第一个格式说明符已损坏。 – 2010-01-21 22:48:14

+0

@尼尔:copula属于Copula类型。 :P见第二段代码的第一行。 – 2010-01-21 23:20:52

sprintf的有4个地方而您仅提供3个参数。

我建议:

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

sprintf不是缓冲区溢出的安全,使用,而C99 snprintfstd::stringstream

+0

普遍认同,除了因为他提供的所有内容都是基于字符的,流是有点矫枉过正的。 – 2010-01-21 21:38:14

+0

问题是C++中的'toString()'是' Artyom 2010-01-21 22:13:27

+0

决定使用'sprintf'或流在很大程度上是一个选择的问题。就我个人而言,我讨厌流媒体。我发现'sprintf'更加简洁并且更容易完全控制输出。 – 2010-01-21 22:49:34

您的格式字符串中有四个说明符,但只提供三个附加参数。

,看起来完全破碎的唯一的事情是,你只有通过3个数据参数传送到您的sprintf,但它预计4(%C,%S,%S,S)

+0

sprintf的第一个格式说明符已损坏。 – 2010-01-21 22:47:21

因为所有的东西你都黏合在一起,是基于字符的,使用的sprintf为它有点傻。

什么是C++程序员应该做的还有线沿线的东西更多:

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

有一点需要注意,在这种情况下,使用ostringstream是一个更好的主意。在这种情况下,这个代码可能是正确的。 – Omnifarious 2010-01-21 21:44:46

+0

“应该”是非常主观和风格的问题。 – 2010-01-21 22:50:24

+0

即使只处理字符串,有一个单独和清晰的格式说明符有时也很有用。我发现长串混杂的字符串连接的序列在眼睛上是痛苦的。通过类似“%c_%s(%s,%s).csv”的内容,您可以立即看到格式规则是什么。通过使用Boost.Format,您可以获得格式说明符的好处,而不会丢失/无效参数的危险。 – 2010-01-21 23:06:49

因为你似乎性病工作::字符串,你不需要用sprintf的。 std :: string有简单的重载操作符,所以你可以使用+ =来连接字符串。我认为+也可以,所以只需将“std :: strings”添加到一起即可。

假设toString()返回std::string

此:

的sprintf(结果, “%C_%S(%S,%S)的.csv”, copula.toString()。 c_str(), left.toString()。c_str(), right.toString()。c_str());

...应该是:

的sprintf(结果, “%S _%S(%S,S)的.csv”, copula.toString()。 c_str(), left.toString()。c_str(), right.toString()。c_str());

+0

约翰,你可能是%s应该是第一个而不是%c,但也许他只想要字符串的第一个字符是正确的。如果是这样,他仍然是错的 - 他传递的是字符串的地址而不是第一个字符。 你真的在这里错过了传递给sprintf的参数数量的错误匹配,三个,当说明符需要四个时。 减去一个给你,如果我可以投票。 – 2010-01-21 23:20:25

Boost有一个formatting library比printf和朋友更安全。

#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()); 
} 

,或者可选地:

#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()); 
} 

对于后者例如,升压知道%1%在类型是字符,并且%2%直通%4%是字符串由 “寻找”通过%运算符传入的参数。

+0

:O Boost总是令我惊讶。 – qba 2010-01-21 23:00:39

+0

每当语言或标准库似乎缺少一个普遍有用的功能时,它有可能在Boost中实现。 :-) – 2010-01-21 23:04:10

+0

boost如何处理第一个参数是%c,传递给它的东西是字符串的地址,而不是char? – 2010-01-21 23:25:37