从 C++ stringstream ostringstream 获取 char* 数组

Getting char* array from c++ stringstream ostringstream

我正在尝试将 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* 数组添加到一个参数中以获得 prefix /path/file.txt suffix

这个问题是出于某种未知的原因,fullFilePath 也变成了 prefix /path/file.txt suffix .代码的最后三行将展示这一点。

我在这上面花了好几个小时,想着这可能是一个参考问题或其他问题。但是,我尝试的 none 起作用了。任何想法如何解决这个问题?

谢谢!!

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

stringstream.str() returns 一个过期值 一个临时字符串对象,其生命周期仅限于表达式的末尾。删除时指向临时过期值的指针将简单地悬挂并且在表达式之外访问它是未定义的行为,可能是崩溃或一些垃圾值。

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

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

}

您正在 return 指向本地对象的指针,该对象的范围未扩展到函数范围之外。更好的建议是 return 来自函数的字符串对象,然后在调用者范围内将字符串对象转换为 const C 空终止字符串。

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 复制字符串,但调用者应该注意释放已分配缓冲区的资源。

简短的回答是您需要使用 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 这个函数的结果,加上它可能 return NULL 有时如果您不对其进行测试,可能会导致混乱。 return std::string.

会好很多

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

只是不要使用 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 指针)