Converting Std: :Wsting to Char* with Wcstombs_S

I have input strings that contain only digits (just the plain Latin ones, 0-9, so for example "0123"), stored as std::wstring, and I need each as a char*. What's the best way for me to do this? This is my initial approach:

void type::convertWStringToCharPtr(_In_ std::wstring input, _Out_ char * outputString)
{
    outputString = new char[outputSize];
    size_t charsConverted = 0;
    const wchar_t * inputW = input.c_str();
    wcstombs_s(&charsConverted, outputString, sizeof(outputString), inputW, input.length());
}

EDIT: The code below works. Thanks all!

void type::convertWStringToCharPtr(_In_ std::wstring input, _Out_ char * outputString)
{
    size_t outputSize = input.length() + 1; // +1 for null terminator
    outputString = new char[outputSize];
    size_t charsConverted = 0;
    const wchar_t * inputW = input.c_str();
    wcstombs_s(&charsConverted, outputString, outputSize, inputW, input.length());
}
5

3 Answers

You are not allocating enough memory for your buffer:

char * outputString = new char[input.length()];

Should be

char * outputString = new char[input.length() + 1];

because of terminating NUL-character.

Oh, and also, as per pm100's comment: sizeof(outputString) is giving you the size of the pointer. You should use input.length() + 1, as that is the size of the buffer.

There are a couple of errors in your code. First, you're not allocating enough space in your destination buffer for the NULL character. You must allocate at least input.length() + 1 chars for the function to succeed.

Second, you're not passing in the correct size of the output buffer to the function. sizeof(outputString) returns the size of outputString itself, a char *, and not the number of bytes pointed to by that pointer.

So your function should look like this:

void CoverageTileManager::convertWStringToCharPtr(_In_ std::wstring input, _Out_ char * outputString)
{
    size_t outputSize = input.length() + 1;
    outputString = new char[outputSize];
    size_t charsConverted = 0;
    wcstombs_s(&charsConverted, outputString, outputSize, input.c_str(), input.length());
    // TODO verify charsConverted = outputSize
}

In C++ I would never use pure pointers: use vector if a char array needed in heap! Do you want to copy the source string? If not, const reference should be used for input. wcstombs_s is used only in Windows, so why doesn't use simply WideCharToMultiByte? Was the conversion success? Return value.

bool CoverageTileManager::convertWStringToCharPtr(const std::wstring& input, std::vector<char>& outputString )
{
    if ( input.empty() ) {
       return false;
    }
    int size = WideCharToMultiByte(CP_ACP,0,input.c_str(),input.size(),NULL,0,NULL,NULL);
    if ( size <= 0 ) {
      return false;
    }
    outputString.resize(size+1);
    if ( WideCharToMultiByte(CP_ACP,0,input.c_str(),input.size(),&outputString[0],size,NULL,NULL) <= 0 ) {
       outputString.clear();
       return false;
    }
    outputString[size] = '\0';
    return true;
}

Use vector to external C++ lib:

extern void call( const char*, size_t);
std::vector<char> buffer;
std::wstring input;
...
if ( convertWStringToCharPtr(input,buffer) ) {
    call(&buffer[0],buffer.size());
}
3

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

James H. Sterling

James H. Sterling

Environmental Science & Climate Journalist

James Sterling reports on renewable energy developments, climate policy, ecological conservation, and green tech innovations around the globe.

Share this article
Twitter Facebook Pinterest