galaxyworks
galaxyworks

Reputation: 331

std::string stops at \0

I am having problems with std::string..

Problem is that '\0' is being recognized as end of the string as in C-like strings.

For example following code:

#include <iostream>
#include <string>

int main ()
{
    std::string s ("String!\0 This is a string too!");
    std::cout << s.length(); // same result as with s.size()
    std::cout << std::endl << s;

    return 0;
}

outputs this:

7
String!

What is the problem here? Shouldn't std::string treat '\0' just as any other character?

Upvotes: 12

Views: 12610

Answers (7)

Joseph Thomson
Joseph Thomson

Reputation: 10393

You are constructing your std::string from a string literal. String literals are automatically terminated with a '\0'. A string literal "f\0o" is thus encoded as the following array of characters:

{'f', '\0', 'o', '\0'}

The string constructor taking a char const* will be called, and will be implemented something like this:

string(char const* s) {
    auto e = s;
    while (*e != '\0') ++e;

    m_length = e - s;
    m_data = new char[m_length + 1];
    memcpy(m_data, s, m_length + 1);
}

Obviously this isn't a technically correct implementation, but you get the idea. The '\0' you manually inserted will be interpreted as the end of the string literal.

If you want to ignore the extra '\0', you can use a std::string literal:

#include <iostream>
#include <string>

int main ()
{
    using namespace std::string_literals;

    std::string s("String!\0 This is a string too!"s);
    std::cout << s.length(); // same result as with s.size()
    std::cout << std::endl << s;

    return 0;
}

Output:

30
String! This is a string too!

Upvotes: 3

Hilton Fernandes
Hilton Fernandes

Reputation: 660

In very few words, you're constructing your C++ string from a standard C string.

And standard C strings are zero-terminated. So, your C string parameter will be terminated in the first \0 character it can find. And that character is the one you explicitly provided in your string "String!\0 This is a string too!"

And not in the 2nd one that is implictly and automatically provided by the compiler in the end of your C standard string.

Upvotes: 0

lowarago
lowarago

Reputation: 88

\0 is known as a terminating character so you'll need to skip it somehow.

String represntation

Take that as an example.

So whenever you want to skip special characters you would like to use two backslashes "\\0"

And '\\0' is a two-character literal

   std::string test = "Test\\0 Test"

Results :

   Test\0 Test

Most beginners also make mistake when loading eg. files :

 std::ifstream some_file("\new_dir\test.txt"); //Wrong
 //You should be using it like this : 
 std::ifstream some_file("\\new_dir\\test.txt"); //Correct

Upvotes: 1

Revolver_Ocelot
Revolver_Ocelot

Reputation: 8785

Think about it: if you are given const char*, how will you detemine, where is a true terminating 0, and where is embedded one?

You need to either explicitely pass a size of string, or construct string from two iterators (pointers?)

#include <string>
#include <iostream>


int main()
{
    auto& str = "String!\0 This is a string too!";
    std::string s(std::begin(str), std::end(str));
    std::cout << s.size() << '\n' << s << '\n';
}

Example: http://coliru.stacked-crooked.com/a/d42211b7199d458d

Edit: @Rakete1111 reminded me about string literals:

using namespace std::literals::string_literals;
auto str = "String!\0 This is a string too!"s;

Upvotes: 17

Simon
Simon

Reputation: 1684

That's not a problem, that's the intended behavior.

Maybe you could elaborate why you have a \0 in your string.

Using a std::vector would allow you to use \0 in your string.

Upvotes: -1

Christian Hackl
Christian Hackl

Reputation: 27528

Your std::string really has only 7 characters and a terminating '\0', because that's how you construct it. Look at the list of std::basic_string constructors: There is no array version which would be able to remember the size of the string literal. The one at work here is this one:

basic_string( const CharT* s,
              const Allocator& alloc = Allocator() );

The "String!\0 This is a string too!" char const[] array is converted to a pointer to the first char element. That pointer is passed to the constructor and is all information it has. In order to determine the size of the string, the constructor has to increment the pointer until it finds the first '\0'. And that happens to be one inside of the array.


If you happen to work with a lot zero bytes in your strings, then chances are that std::vector<char> or even std::vector<unsigned char> would be a more natural solution to your problem.

Upvotes: 4

Random Guy
Random Guy

Reputation: 1134

Escape your \0

std::string s ("String!\\0 This is a string too!");

and you will get what you need:

31
String!\0 This is a string too!

Upvotes: -2

Related Questions