为什么c_str()为两个不同的字符串返回相同的值?

时间:2014-04-11 15:25:46

标签: c++ string

给定一个简单的文件加载功能,

std::string load_file(const std::string &filename) {
    std::ifstream     file(filename);
    std::string       line;
    std::stringstream stream;
    while (std::getline(file, line)) {
        stream << line << "\n";
    }
    return stream.str();
}

为什么以下内容会打印another_file两次的内容?

const char *some_file = load_file("some_file").c_str();
const char *another_file = load_file("another_file").c_str();
printf("%s", some_file);
printf("%s", another_file);

2 个答案:

答案 0 :(得分:14)

代码被破坏了。您正在对立即销毁的临时对象调用c_str()。这意味着c_str()返回的值无效。

您需要确保返回的std::string对象至少在您保持对c_str()的调用返回的指针时保持不变。例如:

std::string some_file = load_file("some_file");
std::string another_file = load_file("another_file");
printf("%s", some_file.c_str());
printf("%s", another_file.c_str());

答案 1 :(得分:3)

在这样的一行:

const char *some_file = load_file("some_file").c_str();

load_file()返回临时 std::string,然后在此临时调用.c_str()

当临时值处于活动状态时,.c_str()返回的指针指向一些有意义的字符串。但是,当临时&#34;蒸发&#34; (在分号处),那个相同的指针指向垃圾。

&#34;垃圾&#34;可能与之前调用load_file()返回的字符串相同,因此您可以看到两个原始指针都指向同一个字符串。 但这只是巧合 你的代码有一个错误。

std::string这样的被发明为简化C ++程序员生活的简便方法,而不是使用原始C字符串指针。因此,如果您想在C ++中安全地管理字符串,请使用std::string

考虑在边界上使用.c_str()只使用C函数(包括printf()

所以,你可以像这样重构你的代码:

// load_file() returns a std::string, so just keep using std::string.
// Note that returning std::string is efficient thanks to RVO/NRVO 
// and C++11 move semantics. 
std::string some_file = load_file("some_file");

// Idem for this:
std::string another_file = load_file("another_file");

// Convert from std::string to raw C string pointers at the C boundary
printf("%s\n", some_file.c_str());
printf("%s\n", another_file.c_str());

即便是这样的代码也能正常工作:

printf("%s\n", load_file("some_file").c_str());
printf("%s\n", load_file("another_file").c_str());

实际上,请注意,在这种情况下,即使您使用临时(即load_file()返回的字符串也不会复制到名为 std::string变量),临时在printf()调用期间有效,因此.c_str()返回的原始指针指向有效字符串,而printf()正在执行其打印作业。