我正在尝试将 ostringstream 复制到 char * 数组,希望有人可以帮助我理解我的错误所在。我查看了论坛,发现了一些类似的东西,不幸的是我仍然无法从ostringstream获取属性副本到char *。总之,我试图通过以下方式复制到char *中:
ostringstream bld
bld<<"test"<<"is"<<"good"
const char * result = bld.str().c_str();
重现错误的完整代码如下。在这段代码中,我有两个基本上通过ostringstream构建字符串的函数。在 makeFilePath()函数中,我构建了一个完整的文件路径(即 /path/file.txt )。在 add()函数中,我只是将两个char *数组添加到参数中以获取前缀/path/file.txt后缀。
问题是由于某些未知原因, fullFilePath 也更改为前缀/path/file.txt后缀。代码的最后三行将显示出来。
我花了好几个小时,想到这可能是一个引用问题或其他问题。但是,我没有尝试过任何工作。任何想法如何克服这个问题?
谢谢!
#include <iostream>
#include <sstream>
#include <string>
using std::cout;
using std::endl;
using std::string;
using std::ostringstream;
const char* add(const char *fileName) {
ostringstream bld;
const char *prefix = "prefix";
const char *suffix = "suffix";
bld << prefix << " " << fileName << " " << suffix;
string temp = bld.str();
cout << "in add(): \n\t" << temp << endl;
return temp.c_str();
}
const char * makeFilePath(const char *path, const char *name, const char *ext =
".txt") {
ostringstream bld;
bld << path << name << ext;
cout << "makeFilePath(), returning: \n\t" << bld.str()<< endl;
string temp = bld.str();
return temp.c_str();
}
int main(int argc, char **argv) {
cout << "=== PROJECT START ===" << endl;
const char * filePath = "\\Path\\";
const char *fileName = "FILENAME";
const char *fullFilePath = makeFilePath(filePath, fileName);
cout << fullFilePath before calling add():\n\t" << fullFilePath << endl;
const char* str = add(fullFilePath);
cout << fullFilePath after calling add():\n\t" << fullFilePath << endl;
return 1;
}
答案 0 :(得分:3)
stringstream.str()返回一个临时值,该临时字符串对象的生命周期限制在表达式的末尾。删除时指向临时过期值的指针只是悬挂并在表达式之外访问它是未定义的行为,可能是崩溃或一些垃圾值。
一种选择是将字符串对象提取为持久字符串,然后获取指向字符数组缓冲区的常量指针。
const std::string bld= stringstream.str();
const char* result= bld.c_str();
或者你也可以考虑将过期的rvalue绑定到一个常量引用(注意某些编译器可能很宽松地绑定到可能不正确的引用),然后获取指向缓冲区的指针。这将简单地延长临时对象的生命周期。
但这并不能解决你所有的痛苦。因为我错过了你的功能实现
const char * makeFilePath(const char *path, const char *name, const char *ext =
".txt") {
ostringstream bld;
bld << path << name << ext;
cout << "makeFilePath(), returning: \n\t" << bld.str()<< endl;
string temp = bld.str();
return temp.c_str();
}
您正在返回一个指向本地对象的指针,该对象的范围未扩展到函数范围之外。更好的建议是从函数返回一个字符串对象,然后在调用者范围内将字符串对象转换为const C null终止字符串。
std::string makeFilePath(const char *path, const char *name, const char *ext =
".txt") {
ostringstream bld;
bld << path << name << ext;
cout << "makeFilePath(), returning: \n\t" << bld.str()<< endl;
return bld.str();
}
或者,您可能希望使用strdup复制字符串,但调用者应该知道为已分配的缓冲区释放资源。
答案 1 :(得分:3)
简短的回答是你需要使用类似strdup
的东西来解决这个问题:
const char* makeFilePath(const char *path, const char *name, const char *ext = ".txt")
{
ostringstream bld;
bld << path << name << ext;
cout << "makeFilePath(), returning: \n\t" << bld.str()<< endl;
return strdup(bld.str().c_str());
}
这是一个非常次优的解决方案,因为现在你有一个内存泄漏,除非你正确地free
这个函数的结果,加上它有时可能会返回NULL
,如果你不这样做可能会导致混乱#39; t测试它。返回std::string
会好得多。
如果您正在使用C ++,请使用C ++。
答案 2 :(得分:1)
不要使用char *
。如果你正在编写C ++,你应该使用C ++字符串,而不是C字符串。
C没有任何东西可以为你复制字符串(除了sprintf
以及NULL-target GNU扩展名?),所以你经常会留下无效的指针。
using std::ostringstream;
using std::string;
string add(const string fileName) {
ostringstream bld;
string prefix = "prefix";
string suffix = "suffix";
bld << prefix << " " << fileName << " " << suffix;
string temp = bld.str();
cout << "in add(): \n\t" << temp << endl;
return temp;
}
string makeFilePath(string path, string name, string ext =
".txt") {
ostringstream bld;
bld << path << name << ext;
cout << "makeFilePath(), returning: \n\t" << bld << endl;
string temp = bld.str();
return temp;
}
int main(int argc, char **argv) { // unfortunately, argv much be char**
cout << "=== PROJECT START ===" << endl;
string filePath = "\\Path\\";
string fileName = "FILENAME";
string fullFilePath = makeFilePath(filePath, fileName);
cout << fullFilePath before calling add():\n\t" << fullFilePath << endl;
string str = add(fullFilePath);
cout << fullFilePath after calling add():\n\t" << fullFilePath << endl;
return 1;
}
这里有一个更广泛的教训,在现代C ++中你可以删除几乎所有指针的使用(不仅仅是char指针)