Sign in to follow this  
sybixsus

Copying std::string To char*

Recommended Posts

I'm writing a simple DLL for learning purposes and because the DLL will export a pure "C" API, which can be called by pretty much any language, I'm having to use char* for all text coming in or going out. Internally, I need to use std::string ( I'm using a std::map and std::string is the key. ) It seems I can copy the text from char* to std::string simply by assigning thus:
std::string S=CharP;
However, I can't do the same to get it back out. I can get a const char* from the c_str() method of std::string, but then I need to copy that to a new char array. However, the string copying is throwing an error indicating that the buffer isn't big enough. So I've got this as a standalone test app :
#include "stdafx.h"
#include "iostream"

using namespace std;


int _tmain(int argc, _TCHAR* argv[])
{
	
	std::string Name="Test";
	int NLen=Name.length();
	char* Result = new char[NLen+1];
	strcpy_s(Result, NLen,Name.c_str());

	cout << Result;

	return 0;
}


I've checked the assignment, and the length, and that's all working fine. So I guess it's purely that NLen+1 isn't big enough, but I'm not sure why it isn't big enough. NLen has a value of 4, and you need one more for the null termination character. What else do I need? I assume that std::string uses single byte strings, because there is a std::wstring for wide strings.

Share this post


Link to post
Share on other sites
Is the 'number of elements' argument to strcpy_s() correct? It seems it should be:
strcpy_s(Result, NLen+1,Name.c_str());
If that doesn't fix it, perhaps you could post the error that you're getting.

Share this post


Link to post
Share on other sites

#include <iostream>
#include <string>

int main()
{
std::string Name="Test";
char* Result = new char[Name.length()+1];
strcpy(Result,Name.c_str());

std::cout << Result;

return 0;
}



note the <> and the lack of .h in the includes. That's the way those includes should be called.

Share this post


Link to post
Share on other sites
The strcpy_s call works differently than you are using it. The second parameter is the total size of the buffer, not how many bytes you wish to fill. Since you are telling the function the size of the buffer is 4, yet the function needs to write 5 bytes (4 + null), the function fails.

strcpy_s(Result, NLen + 1, Name.c_str()); will fix it and is correct.

[lol] 3 replies in less than 30 seconds of the same minute.

Share this post


Link to post
Share on other sites
Alternately, use a std::vector to perform allocation and copying as part of the constructor:

std::string Name="Test";
std::vector<char> buffer(Name.c_str(), Name.c_str() + Name.length() + 1);

Share this post


Link to post
Share on other sites
You do know that std::string has a copy function that will fill a supplied buffer for you without the (potential) problem of extra dynamic allocations and copying that result from the use of its c_str() member function?

In C++ you are almost always better off using C++ to write your code than importing foreign ideas like the C standard library and trying to retrofit your square peg into the language's round hole. std::vector is better than new char[] for many many reasons.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
Alternately, use a std::vector to perform allocation and copying as part of the constructor:

std::string Name="Test";
std::vector<char> buffer(Name.c_str(), Name.c_str() + Name.length() + 1);


I think this is not good way how to copy string to vector - I think c_str() method can return different pointer each time it is called.

Better is just use string iterators:
std::vector<char> buffer(Name.begin(), Name.end());

Share this post


Link to post
Share on other sites
Quote:
Original post by bubu LV
I think this is not good way how to copy string to vector - I think c_str() method can return different pointer each time it is called.

The pointer returned by c_str() is guaranteed to be valid until the next non-const member function is called. c_str() is const.

Quote:
Better is just use string iterators:

You don't get the null terminator that way.

Share this post


Link to post
Share on other sites
Thanks guys, I didn't realise that I was supposed to include the null terminator when telling strcpy_s the size. I assumed that, since the null was fixed that it was not included in the size.

Point taken about the headers. I was only knocking up a quick test app, so I didn't change what Visual Studio gave me, but I should get used to writing my includes in C++ rather than C.

With regard to using a vector and dynamic allocation, I'm actually going to need to return the copied string out of my DLL, and again that has to be a pure C API, so char* is the preferable way to do that. I could wrap std::vector but if I was going to do that, why not wrap std::string? People calling the DLL in other languages won't want to create an object every time they want to set or get a name, they'll expect to use a string literal, and for that reason, I'm sticking with char*. If there's something I'm not seeing here about sending and receiving strings to and from a DLL without having to wrap std::string or std::vector then by all means point me at it, but with what I know, char* seems the best way.

Yes, I saw that std::string has a copy method but it didn't look like it could be used to copy to a char[] and when I searched on this forum and others for the best way to copy from std::string to char[], the answer was always strcpy. Since the compiler told me that strcpy was deprecated and I should use strcpy_s, that's what I did.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
With a vector<char>, you can get a char * with &*begin() or &vec[0].


Which is why std::vector can be very useful for working with C APIs -- yes, the C++ standard guarantees this works. The only noteworthy wart is that you'll have to manually handle the case when vec.size() == 0, if that can ever occur in your program, as *begin() and vec[0] both invoke Undefined Behavior in that case.

(And, of course, resizing the vector may force it to reallocate which will in turn change the pointer returned and make the old one invalid)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this