2

我正在尝试将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也更改为看起来像prefix /path/file.txt suffix。代码的最后三行将展示这一点。

我花了几个小时在这上面,想也许这是一个参考问题或别的什么。但是,我尝试过的都没有。任何想法如何克服这个问题?

谢谢!!

#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;
}
4

3 回答 3

4

stringstream.str() 返回一个过期值一个临时字符串对象,它的生命周期被限制在表达式的末尾。删除时指向临时到期值的指针只会悬空,并且在表达式之外访问它是未定义的行为,可能是崩溃或一些垃圾值。

一种选择是将字符串对象获取到持久字符串,然后获取指向字符数组缓冲区的常量指针。

const std::string bld= stringstream.str();
const char* result= bld.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();

}

您正在返回一个指向本地对象的指针,该对象的范围未超出函数范围。更好的建议是从您的函数返回一个字符串对象,然后在调用者范围内将该字符串对象转换为一个 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 复制字符串,但调用者应该知道为分配的缓冲区释放资源。

于 2015-04-22T15:49:40.603 回答
4

简短的回答是你需要使用类似的东西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有时可能会返回,如果你不测试它可能会导致混乱。回去会好很多std::string

如果您使用 C++,请使用 C++。

于 2015-04-22T15:55:39.400 回答
2

只是不要使用char *. 如果您正在编写 C++,则应该使用 C++ 字符串,而不是 C 字符串。

C 没有任何东西可以为你复制字符串(除了可能sprintf带有 NULL 目标的 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 指针)

于 2015-04-22T16:03:05.853 回答