从c ++函数返回字符串时出现分段错误

时间:2014-07-31 05:17:47

标签: c++

我班上有错误。 我怀疑它很简单,也许我无法理解字符串在C ++中是如何工作的。 我的函数尝试将本地std :: string返回到另一个std :: string,但是在函数返回后我得到了分段错误,而不是获取字符串。 这是我的代码:

    TestClass::TestClass(std::string a, std::string b)
    {
        m_a = a;
        m_b = b;
    }

    std::string TestClass::stringHandler()
    {
        const char myTemplate[] = "a=%s,b=%s";
        char formattedString[strlen(myTemplate) + m_a.length() + m_b.length()];
        sprintf( formattedString, myTemplate, m_a.c_str(), m_b.c_str());
        std::cout << "formattedString= " << formattedString << "\n";
        std::string returnStr(formattedString);
        std::cout << "returnStr=" << returnStr << "\n";
        return returnStr;
    }

    int main(...)
    {
        /* getting a and b from argv */
        TestClass MyClassObj(a, b);
        std::string strRet = MyClassObj.stringHandler();
        std::cout << "Back after stringHandler\n";
        return 0
    }

在stringHandler中,当我打印returnStr时,它会正确显示。 但就在那之后,我遇到了分段错误,并且没有打印“返回stringHandler之后”。 你们中的任何人都掌握了,知道我做错了什么吗?

1 个答案:

答案 0 :(得分:3)

几个问题:

  • %b不是有效的格式说明符。
  • 您有3个格式说明符(如果%b已修复!)但您只传递了2个参数。
  • 您没有为formattedString分配足够的内存。
  • 运行时大小的数组在C ++中是非法的
在对OP进行编辑之后

(更新:),其中前三个是固定的,因此如果您的编译器还具有运行时数组大小的扩展,那么此代码不会导致段错误。 / p>

最简单的解决方法就是写:

std::string returnStr = "a=" + m_a + ",b=" + m_b;

但假设你想坚持使用printf格式,这是一种方法。 虽然可以计算并计算出确切的空间量,但这很脆弱。如果您对myTemplate进行了更改,则很容易导致缓冲区溢出。

一个计划是分配大量空间。更健壮的方法是首先使用snprintf来确定缓冲区大小:

char const myTemplate[] = "a=%s,b=%s";
size_t expect_len = std::snprintf(NULL, 0, myTemplate, m_a.c_str(), m_b.c_str());

if ( expect_len == -1 )
    throw std::runtime_error("snprintf failed");

std::vector<char> buffer(expect_len + 1);
std::snprintf(&buffer[0], buffer.size(), myTemplate, m_a.c_str(), m_b.c_str());

std::string returnStr(buffer);

在C ++ 11中,您实际上可以snprintf直接进入returnStr

要明确的是,整个printf的想法并不是非常安全,因为如果myTemplate包含您不期望的内容,则会导致未定义的行为。 (我假设你这样做是为了让你自己在运行时指定一个不同的格式字符串)。所以要谨慎使用它。