【问题标题】:Conditional jump valgrind with char* and << operator带有 char* 和 << 运算符的条件跳转 valgrind
【发布时间】:2012-09-26 18:07:24
【问题描述】:

我正在编写我的 String 类版本,但 Valgrind 抱怨我为我的字符串实现了 &lt;&lt; 运算符。错误出现在错误的行,如果我按字符打印,效果很好。

我哪里错了?

Valgrind 错误:

==2769== 条件跳转或移动取决于未初始化的值

==2769== at 0x4C2AC28: strlen(在 /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so 中)

==2769== by 0x4ECAD60: std::basic_ostream >& std::operator(std::basic_ostream >&, char const*) (in /usr/lib/x86_64-linux-gnu/libstdc++ .so.6.0.17)

==2769== by 0x400BD5: operator

==2769== by 0x400AAC: main (main.cpp:12)

我的&lt;&lt; 字符串运算符:

ostream & operator << (ostream & o, String & inS) {
    o << inS._pData << " "; // the wrong line
    return o;
}

我的String 班级:

class String {
    public:
         unsigned _size;
         char *   _pData;
         String();
         String(const char* inCString);
};

构造函数(用于char*):

String::String(const char* inCString) {
    _size = strlen(inCString);
    _pData = new char[_size + 1];
    strncpy(_pData, inCString, _size);
}

Main.cpp:

int main(int, char**) {
    String s1("hello");
    cout << s1;
    return 0;
}

【问题讨论】:

  • 请问您为什么要麻烦重新实现字符串?
  • 你服从Rule of Three了吗?
  • @MooingDuck :是的,但不是整个代码都在这里;只有相关的。
  • @Benj :这是一个课堂作业;我们第一个月的cpp,为什么要你知道?
  • @Cqnqrd 课业是完全正当的理由,如果你要在生产代码中这样做,我会称你为疯子 ;-)

标签: c++ string valgrind cout strcpy


【解决方案1】:

我不建议使用这样的原始字符串。

然而,罪魁祸首在这里:

strncpy(_pData, inCString, _size+1);

或者,或者,手动存储 NUL 终止字符:

_pData[_size] = 0;

由于缺少 NUL 终止字符,输出操作将继续运行超过字符串的末尾。 (该行为可能看起来不错,因为该字符可能偶然为 nul,具体取决于编译器、选项等)

提示:

  • 考虑使用 C++ 风格而不是 C API
  • 如果你必须使用C风格的char*,至少使用stdrupfree
  • 如果您坚持使用以 NUL 结尾的字符串,请考虑也使用 C++ 方式编写:

    #include <iostream>
    #include <vector>
    
    class String
    {
    public:
        std::vector<char> _data;
        String();
        String(const char* inCString);
    };
    
    std::ostream & operator << (std::ostream & o, String const& inS)
    {
        o.write(inS._data.data(), inS._data.size());
        return o << ' ';
    }
    
    String::String(const char* inCString)
    {
        for (const char* it=inCString; it && *it; ++it)
            _data.push_back(*it);
    }
    
    int main(int, char**)
    {
        String s1("hello");
        std::cout << s1;
        return 0;
    }
    

【讨论】:

  • @cqnqrd 你还应该小心在你的构造函数中用一个空的(以null结尾的)字符串初始化_pData,没有参数
  • 确实我必须使用 char*(学生),但感谢您的建议,我会练习的。
【解决方案2】:

请注意,您并未显式初始化数据成员,而是为它们分配了一个值:

...为了初始化,您应该更改为:

String::String(const char* inCString) :
    _size(strlen(inCString)),
    _pData(new char[_size + 1])
{
    strncpy(_pData, inCString, _size);
}

【讨论】:

  • 这与OP的问题无关。
  • @penelope:不,他们不是。整数和指针初始化,除非显式构造,例如C::C() : m_size(), m_ptr() {}
  • @penelope,它们是 POD 类型,因此不调用默认构造函数。 _size 值未定义,_pData 指向垃圾。
【解决方案3】:

因为你没有在最后写入零字节。你需要:

strncpy(_pData, inCString, _size + 1);
//                              ^^^^

对于 C 字符串函数的 n 版本,您应该始终非常小心 read the manual,因为它们都有细微的不同语义。

【讨论】:

  • 哦,好的,我也需要复制它。谢谢你的建议,我现在会认真做的。
猜你喜欢
  • 1970-01-01
  • 2015-08-04
  • 2020-07-20
  • 2016-09-27
  • 1970-01-01
  • 2012-03-09
  • 2020-04-15
  • 2021-12-16
  • 2011-04-28
相关资源
最近更新 更多