11

There are two string variables, m and n:

#include <string>

string m = "0100700\0"
cout << m.size() << endl; // it prints: 7

string n;
n += "0100700"
n += '\0';
cout << n.size() << endl; // it prints: 8

I supposed that both had 8 characters, but m had only 7 characters and n had 8 characters. Why is this the case?

Paweł Obrok
  • 22,568
  • 8
  • 74
  • 70
  • You do not need the explicit null character as it is already there – Ed Heal May 16 '15 at 07:45
  • I'm sorry for duplicate question. From now I try to solve my question by searching more carefully. –  May 17 '15 at 09:21

2 Answers2

10

The first thing to note is that std::string does not have a constructor that can infer the length of a string literal from the underlying array. What it has is a constructor that accepts a const char* and treats it as a null-terminated string. In doing so, it copies characters until it finds the first \0.

This is the constructor used in string m = "0100700\0";, which is why in the first case your string is of length 7. Note that there is no other way to get the length of a char array from a pointer to its first element.

In the second example, you add a character to a pre-existing std::string object of length 7. This increases the length to 8. If you were to iterate over the elements of the string, you would be able to see that this 8th element is '\0'.

for (auto c: n)
    if (c == 0) std::cout << "null terminator" << std::endl;

In order to initialize a string containing '\0' characters, you have options:

Use an initialization list:

std::string s{'a', 'b', '\0', 'd', 'e', '\0', 'g'};

Construct from a different container or array using std::string's iterator constructor:

std::vector<char> v{'a', 'b', '\0', 'd', 'e', '\0', 'g'};
char c[] = {'a', 'b', '\0', 'd', 'e', '\0', 'g'};
const char* ps = "ab\0de\0g";

std::string s0(std::begin(v), std::end(v));
std::string s1(std::begin(c), std::end(c));
std::string s2(ps, ps + 8);
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • Thank you very much! Now I understand why that happens. Is there any way to initialize std::string with string that contains null characters? –  May 16 '15 at 06:59
  • @carrot031 You can say for example `string s{'a', 'b', '\0', 'd', 'e', '\0', 'g'};` – juanchopanza May 16 '15 at 07:02
  • Would be better to use the iterator constructor, as pointers are valid random-access iterators. – Puppy May 16 '15 at 07:27
8

In the 1st sample

 string m = "0100700\0";

The string variable is constructed from a character literal, and takes all characters up to the first '\0' character found.

The 2nd sample nevertheless shows, that you can add an arbitrary number of additional '\0' characters to a std::string and increase it's size.


To answer the question from your comment:

To initialize a string from a literal containing '\0'characters you cain either specify the count explicitly

string m("0100700\0",8);

or you can use the constructor using a first and last iterator:

 const char x[] = "0100700\0";
 string m(std::begin(x),std::end(x));
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • Thank you very much for your quick answer! Is there any way smart way to initialize std::string with a string that contains null characters? –  May 16 '15 at 07:03
  • It looks more readable! I'll use that. I have been trying to make a c++ library for creating tar archives. –  May 16 '15 at 07:16