34

What is the correct/best/simplest way to convert a c-style string to a std::string.

The conversion should accept a max_length, and terminate the string at the first \0 char, if this occur before max_length charter.

Allan
  • 4,562
  • 8
  • 38
  • 59

6 Answers6

31

This page on string::string gives two potential constructors that would do what you want:

string ( const char * s, size_t n );
string ( const string& str, size_t pos, size_t n = npos );

Example:

#include<cstdlib>
#include<cstring>
#include<string>
#include<iostream>
using namespace std;

int main(){

    char* p= (char*)calloc(30, sizeof(char));
    strcpy(p, "Hello world");

    string s(p, 15);
    cout << s.size() << ":[" << s << "]" << endl;
    string t(p, 0, 15);
    cout << t.size() << ":[" << t << "]" << endl;

    free(p);
    return 0;
}

Output:

15:[Hello world]
11:[Hello world]

The first form considers p to be a simple array, and so will create (in our case) a string of length 15, which however prints as a 11-character null-terminated string with cout << .... Probably not what you're looking for.

The second form will implicitly convert the char* to a string, and then keep the maximum between its length and the n you specify. I think this is the simplest solution, in terms of what you have to write.

Vlad
  • 18,195
  • 4
  • 41
  • 71
14
std::string str(c_str, strnlen(c_str, max_length));

At Christian Rau's request:

strnlen is specified in POSIX.1-2008 and available in GNU's glibc and the Microsoft run-time library. It is not yet found in some other systems; you may fall back to Gnulib's substitute.

Community
  • 1
  • 1
ephemient
  • 198,619
  • 38
  • 280
  • 391
5
std::string the_string(c_string);
if(the_string.size() > max_length)
    the_string.resize(max_length);
Daniel
  • 30,896
  • 18
  • 85
  • 139
5

This is actually trickier than it looks, because you can't call strlen unless the string is actually nul terminated. In fact, without some additional constraints, the problem practically requires inventing a new function, a version of strlen which never goes beyond the a certain length. However:

If the buffer containing the c-style string is guaranteed to be at least max_length char's (although perhaps with a '\0' before the end), then you can use the address-length constructor of std::string, and trim afterwards:

std::string result( c_string, max_length );
result.erase( std::find( result.begin(), result.end(), '\0' ), result.end() );

and if you know that c_string is a nul terminated string (but perhaps longer than max_length, you can use strlen:

std::string result( c_string, std::min( strlen( c_string ), max_length ) );
James Kanze
  • 150,581
  • 18
  • 184
  • 329
0

There is a constructor accepting two pointer parameters, so the code is simply

 std::string cppstr(cstr, cstr + min(max_length, strlen(cstr)));

this is also going to be as efficient as std::string cppstr(cstr) if the length is smaller than max_length.

6502
  • 112,025
  • 15
  • 165
  • 265
  • You could also use the constructor taking a pointer and a length, no need for the pointer arithmetic (though it won't be much different). And technically it doesn't take two pointer parameters, but two iterator parameters. And by the way, it won't be as efficient, as it is O(2n) instead of O(n) and constants matter, but it's of course still a correct solution. – Christian Rau Nov 14 '11 at 19:02
  • @ChristianRau: One scan is necessary with a C string to know the length (how much to allocate) but there's no need for a second one (the constructor could just subtract two pointers to get the size). So there is one scan for length and one scan for copy: this is the minimum you can do unless you accept wasting space. – 6502 Nov 14 '11 at 19:22
-2

What you want is this constructor: std::string ( const string& str, size_t pos, size_t n = npos ), passing pos as 0. Your const char* c-style string will get implicitly cast to const string for the first parameter.

const char *c_style = "012abd";
std::string cpp_style = std::string(c_style, 0, 10);

UPDATE: removed the "new" from the cpp_style initialization

kbyrd
  • 3,321
  • 27
  • 41