Reputation: 1114
I'm coding my version of the String class, but Valgrind whines about my implementation of the <<
operator for my string. The error is at the wrong line, if I print char by char it works great.
Where am I wrong?
Valgrind error:
==2769== Conditional jump or move depends on uninitialised value(s)
==2769== at 0x4C2AC28: strlen (in /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<<(std::ostream&, String&) (string.cpp:22)
==2769== by 0x400AAC: main (main.cpp:12)
My <<
operator for string:
ostream & operator << (ostream & o, String & inS) {
o << inS._pData << " "; // the wrong line
return o;
}
My String
class:
class String {
public:
unsigned _size;
char * _pData;
String();
String(const char* inCString);
};
Constructor (for 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;
}
Upvotes: 3
Views: 1152
Reputation: 393684
I don't recommend using raw strings like this.
However, the culprit is here:
strncpy(_pData, inCString, _size+1);
Or, alternatively, store the NUL-termination character manually:
_pData[_size] = 0;
By missing the NUL-termination character, the output operation will just keep on running past the end of the string. (The behaviour may happen to look okay, since the character may be nul by chance, depending on compiler, options etc.)
Hint:
char*
, at least use stdrup
and free
if you insist on doing NUL-terminated strings, consider writing that the C++ way too:
#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;
}
Upvotes: 10
Reputation: 477474
Because you fail to write the zero byte at the end. You need:
strncpy(_pData, inCString, _size + 1);
// ^^^^
You should always read the manual very carefully with the n
-versions of C string functions, since they all have subtly different semantics.
Upvotes: 1
Reputation: 14799
Notice that you are not explicit initializing your data members, you are assigning a value to them:
...in order to initialize, you should change to:
String::String(const char* inCString) :
_size(strlen(inCString)),
_pData(new char[_size + 1])
{
strncpy(_pData, inCString, _size);
}
Upvotes: -1