2010-01-21 90 views
1

我是一個缺乏經驗的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

回答

14

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()'是'<<'。提供'toString()'成員是錯誤的 - 它不是Java或C#。 Ireamream更靈活。 – Artyom 2010-01-21 22:13:27

+0

決定使用'sprintf'或流在很大程度上是一個選擇的問題。就我個人而言,我討厭流媒體。我發現'sprintf'更加簡潔並且更容易完全控制輸出。 – 2010-01-21 22:49:34

5

您的格式字符串中有四個說明符,但只提供三個附加參數。

3

,看起來完全破碎的唯一的事情是,你只有通過3個數據參數傳送到您的sprintf,但它預計4(%C,%S,%S,S)

+0

sprintf的第一個格式說明符已損壞。 – 2010-01-21 22:47:21

13

因爲所有的東西你都黏合在一起,是基於字符的,使用的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

4

因爲你似乎性病工作::字符串,你不需要用sprintf的。 std :: string有簡單的重載操作符,所以你可以使用+ =來連接字符串。我認爲+也可以,所以只需將「std :: strings」添加到一起即可。

2

假設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

3

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