2012-08-05 102 views
4

我是一个C/C++初学者,尝试构建一个看起来像一个非常简单的程序:它将一个文件加载到一个c字符串中(const char *) 。然而,尽管该程序非常简单,但它并不以我理解的方式工作。请看:C字符串与const char *混淆了我...请帮助

#include <iostream> 
#include <fstream> 

std::string loadStringFromFile(const char* file) 
{ 
    std::ifstream shader_file(file, std::ifstream::in); 
    std::string str((std::istreambuf_iterator<char>(shader_file)), std::istreambuf_iterator<char>()); 
    return str; 
} 

const char* loadCStringFromFile(const char* file) 
{ 
    std::ifstream shader_file(file, std::ifstream::in); 
    std::string str((std::istreambuf_iterator<char>(shader_file)), std::istreambuf_iterator<char>()); 
    return str.c_str(); 
} 

int main() 
{ 
    std::string hello = loadStringFromFile("hello.txt"); 
    std::cout << "hello: " << hello.c_str() << std::endl; 

    const char* hello2 = loadCStringFromFile("hello.txt"); 
    std::cout << "hello2: " << hello2 << std::endl; 

    hello2 = hello.c_str(); 
    std::cout << "hello2 = hello.c_str(), hello2: " << hello2 << std::endl; 

    return 0; 
} 

输出看起来是这样的:

hello: Heeeeyyyyyy 

hello2:  青! 
hello2 = hello, hello2: Heeeeyyyyyy 

初始hello2值的每一次变化,总有一些随机的汉字(我用的是日本的电脑,所以我猜这就是为什么它是汉字)。

在我的天真视图中,似乎两个值应该打印相同。一个函数返回一个C++字符串,然后我将其转换为一个c字符串,另一个函数加载该字符串,将该字符串转换并返回。我确信,该​​字符串被正确地加载在loadCStringFromFile由couting的价值之前,我回来了一下,确实是我所想象的,例如:

/*(inside loadCStringFromFile)*/ 
const char* result = str.c_str(); 
std::cout << result << std::endl;//prints out "Heeeyyyyyy" as expected 
return result; 

那么,为什么值的变化?感谢您的帮助...

+0

在loadCStringFromFile中,将文本加载到本地变量,然后返回该变量的内部缓冲区。当函数结束时,你有一个指向释放内存的指针(它是垃圾)。用std :: string你会返回一个完整的有效副本。 – 2012-08-05 10:18:06

+1

我还没有看到你的问题,但+1 *仅用于*你的第一段。它写得很好(至少与StackOverflow中的大多数其他类似问题相比)。我希望你得到一个真棒答案,并继续回来问更多的问题! :) – Mehrdad 2012-08-05 10:45:57

+0

由于这个问题是'C++'标记的,我建议将来不要使用没有很好理由的C字符串。 std :: string对于大多数程序(有时甚至更多)是高效的。 – MasterMastic 2012-08-05 11:40:42

回答

3

功能

std::string loadStringFromFile(const char* file) 

字符串超出范围,即之前返回其复制在函数内部创建的字符串的字符串拷贝函数结束,这就是为什么它的工作原理。

const char* loadCStringFromFile(const char* file) 

,另一方面返回一个指向本地字符串,超出范围时,函数返回,被销毁因此返回地址,const char*,指向某个不确定的。

为了第二种方式调用函数之前工作的您可能需要创建的字符串:

const char* loadCStringFromFile(const char* file, string& str); // return str.c_str() 

.. 
string str; 
const char* result = loadCStringFromFile(file,str); 

,或者你创建的功能堆一个字符串,并通过返回的地址,但有点麻烦,因为调用者需要删除字符串以避免memleak。

4

您的问题是strloadCStringFromFile是一个局部变量,并在函数返回时被破坏。此时从c_str()返回的值无效。

更多细节here

你的第一个功能,loadStringFromFile,是一个比较C++ - 这样做的方式一样,并说明你有一类的利益管理内存。如果你使用char *,那么你必须更加关心内存分配和释放的地方。

+0

阅读这篇文章的人很方便:在调用'c_str'的​​时候,有90%的时间只能用作函数的参数,就像输入一样。如果遵循此规则,并且不尝试将结果存储在局部变量中或从函数返回结果,则很难出错。 (唯一的例外是,如果你传递*字符串本身*以及'char *'作为另一个参数,在这种情况下,这个别名最好是'const'。) – Mehrdad 2012-08-05 10:50:42

-1

你应该重复str.c_str的输出():

return strdup(str.c_str); 

功能strdup可以为c_string头被发现。

+0

这并不真正解释OP是什么发生在他的例子中,虽然可能是一个可能的解决方案(不一定是最好的)。 – 2012-08-05 10:20:27

+0

如果调用方不“免费”,则会发生泄漏。 – Mat 2012-08-05 11:31:18