Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

copying from a std::string to a char array and null-terminating the result

Tags:

c++

string

I have a Visual Studio 2008 C++03 application where I want to copy from a std::string to a char array, but I need the char array to be null terminated even if it must truncate the string to do so.

This, for instance works as desired:

inline void CopyAndNullTerminate( const std::string& source, 
                                  char* dest, 
                                  size_t dest_size )
{
    source.copy( dest, dest_size );
    using std::min;
    char* end = dest + min( dest_size - 1, source.size() );
    *end = '\0';
}

int main()
{
    enum{ MAX_STRING_SIZE = 15 };
    char dest[ MAX_STRING_SIZE ];
    std::string test = "This is a test";

    CopyAndNullTerminate( test, dest, MAX_STRING_SIZE );

    assert( strcmp( test.c_str(), dest ) == 0 );
    return 0;
}

example: http://ideone.com/0EBYb

Is there a shorter, more efficient method of doing this?

Thanks

like image 410
PaulH Avatar asked Jun 05 '12 18:06

PaulH


2 Answers

Yes, use strncpy, defined in cstring:

void copyString(const std::string& input, char *dst, size_t dst_size)
{
    strncpy(dst, input.c_str(), dst_size - 1);
    dst[dst_size - 1] = '\0';
}

Note that for some implementations of std::string (as pointed out by @K-ballo), this may be shorter, but less efficient. This is due to the fact that std::string is NOT guaranteed to be implemented using C-syle strings, although for most situations that is probably the case.

like image 143
Richard J. Ross III Avatar answered Nov 15 '22 07:11

Richard J. Ross III


Assuming that dest_size is guaranteed to be at least 1 (which seems reasonable to me, since otherwise it is not possible to copy and null terminate anything into the buffer):

inline void CopyAndNullTerminate( const std::string& source, 
                                  char* dest, 
                                  size_t dest_size )
{
    dest[source.copy(dest, dest_size-1)] = 0;
}

In C++11, and in all actively-maintained C++03 implementations (including Visual Studio), std::string has contiguous storage, just like std::vector. Thus, you could use memcpy instead of std::string::copy and compare performance.

Likewise you can compare strncpy, std::copy, std::copy_n, strcpy_s, and possibly others I've forgotten, see which is best optimized. In each case, you can compute the number of bytes to copy as std::min(source.size(), dest_size-1). That also avoids the most inefficient case of strncpy (copying a small string into a large buffer).

When doing all these, you can rely on the fact that it is valid to call source[0] even if source is an empty string.

like image 31
Steve Jessop Avatar answered Nov 15 '22 08:11

Steve Jessop