5

I have a fixed length character array I want to assign to a string. The problem comes if the character array is full, the assign fails. I thought of using the assign where you can supply n however that ignores \0s. For example:

std::string str; char test1[4] = {'T', 'e', 's', 't'}; str.assign(test1); // BAD "Test2" (or some random extra characters) str.assign(test1, 4); // GOOD "Test" size_t len = strlen(test1); // BAD 5 char test2[4] = {'T', 'e', '\0', 't'}; str.assign(test2); // GOOD "Te" str.assign(test2, 4); // BAD "Tet" size_t len = strlen(test2); // GOOD 2 

How can I assign a fixed length character array to a string correctly for both cases?

3
  • can't you just include a \0 in each array? Commented Aug 13, 2012 at 13:05
  • Not if the array is full, like in the example. It is a fixed size array for serialization. Commented Aug 13, 2012 at 13:12
  • 1
    yes, but I mean, if you know their size in advance, then you probably know the size of the data they will hold. Why not to increase each of them by 1 char, and put a \0 there? I believe rewriting a couple of lines in the code is easier than having to iterate through the arrays each time. Commented Aug 13, 2012 at 13:16

6 Answers 6

10

Use the "pair of iterators" form of assign.

str.assign(test1, std::find(test1, test1 + 4, '\0')); 
Sign up to request clarification or add additional context in comments.

Comments

2

Character buffers in C++ are either-or: either they are null terminated or they are not (and fixed-length). Mixing them in the way you do is thus not recommended. If you absolutely need this, there seems to be no alternative to manual copying until either the maximum length or a null terminator is reached.

for (char const* i = test1; i != test1 + length and *i != '\0'; ++i) str += *i; 

4 Comments

I was hoping to avoid something like that. Currently what I have for test code is using strncpy into another fixed array that 1 character longer (NULL terminated), then doing the assign. Works for both cases, I just don't like doing extra copies. Your loop does avoid an extra copy, so I do like it better. Surprised there isn't a method the stops when a NULL terminator is found, or n is reached.
In C++11, you can safely resize the string and strncpy into it (using &str[0] as the starting pointer) because C++11 guarantees contiguous internal storage for std::string. Unfortunately, C++03 doesn’t offer such a guarantee.
@steveo225: I'm not. It's only typical you have to implement niché use cases yourself as non-member functions when it comes to STL.
@steveo225 Something else, it’s not a NULL terminator. A null pointer is conceptually different from a null character. Although C++ usually #defines NULL as equivalent to an (unsigned) integer 0 literal, so they appear equivalent. But that’s an error.
0

You want both NULL termination and fixed length? This is highly unusual and not recommended. You'll have to write your own function and push_back each individual character.

1 Comment

It is not highly unusual. It is part of a serialized message that is used for socket transmission and file I/O. The problem is only visible when the character array is completely filled.
0

For the first case, when you do str.assign(test1) and str.assign(test2), you have to have /0 in your array, otherwise this is not a "char*" string and you can't assign it to std::string like this.

Comments

0

saw your serialization comment -- use std::vector<char>, std::array<char,4>, or just a 4 char array or container.

Comments

-1

Your second 'bad' example - the one which prints out "Tet" - actually does work, but you have to be careful about how you check it:

str.assign(test2, 4); // BAD "Tet" cout << "\"" << str << "\"" << endl; 

does copy exactly four characters. If you run it through octal dump(od) on Linux say, using my.exe | od -c you'd get:

0000000 " T e \0 t " \n 0000007 

2 Comments

The example was to show that assign did not stop when it hit the \0, not what the contents were, including non-printable characters.
@steveo225: so you need to copy up to a fixed limit or \0 whichever comes first? Apologies - didn't grasp that from the Q.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.