• Advertisement
Sign in to follow this  

std::string to char*

This topic is 4225 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying to turn a std::string that I used for my function arguement into a char * to use as an arguement to another function. I tried using .c_str, but that returns a const char * (say, why can't you assign a char * to the value of a const one?). How can I get around this problem?

Share this post


Link to post
Share on other sites
Advertisement
A simple (char*) cast should work, but why do you want to convert it to a non-const string? You shouldn't modify the data directly. If you need to modify the data inside of a function, pass a const std::string reference instead of a char pointer.

Share this post


Link to post
Share on other sites
Quote:
Original post by Programmer16
A simple (char*) cast should work, but why do you want to convert it to a non-const string? You shouldn't modify the data directly. If you need to modify the data inside of a function, pass a const std::string reference instead of a char pointer.

No, no, no. You should never cast away constness like that, even if you're 'sure' that your function never modifies the data. You are just undermining the security features of the language if you do that. If you really want to modify it, make a copy or else just have your function take a const char* as well.

Share this post


Link to post
Share on other sites
I can't say I'd recommend the doing any const casting trickery, since the internals of basic_string are mostly left up to the implementation. If you really must pass a non-const character pointer to a string, you can do something along these lines:

#include <iostream>
#include <string>
#include <vector>

int main() {
// A string
std::string s("Testing");

// Copy s into a vector, then add a null terminator
std::vector <char> v(s.begin(), s.end());
v.push_back(char(0));

// And, finally, direct access to a pointer
char *v_str = &v[0];

// Let's print it out for some reason
std::cout << v_str << std::endl;

// Say you need to put it back into the string now (edit: I like this way better, actually)
s.assign(&v[0], v.size()-1);
}


Share this post


Link to post
Share on other sites
I'm not entirely sure what you mean by that, so let me show you what I'm trying to do.

GLuint LoadGLTexture(std::string loader)
{
ilInit();
iluInit();
ilutRenderer(ILUT_OPENGL);
ilutInit();

loader = "Data/" + loader + ".bmp";
ILholder = loader;
texture = ilutGLLoadImage(ILholder);

return texture;
}

I'm wanting the std::string to do the concatenation. ILholder is a char *, which is what ilutGLLoadImage takes as a parameter. However, I can't get ILholder to be assigned loader. Also, I don't want to use const char *'s so that I can just make one, and not have to make a new one every time I call LoadGLTexture (which I do once a frame), because it's my understanding that'll drastically slow my program down.

Share this post


Link to post
Share on other sites
Okay, so (a) you need a string concatenation method and (b) you're just trying to interact with a function that should have its parameter declared const if it wasn't trying to be old-C compatible.

You can cheat in that case, I suppose :).

#include <sstream>

// ...

GLuint LoadGLTexture(const std::string &loader)
{
// ...

std::ostringstream sstr;
sstr << "Data/" << loader << ".bmp";
std::string str(sstr.str());

return ilutGLLoadImage(const_cast<char *>(str.c_str()));
}

Share this post


Link to post
Share on other sites
People have been complaining about this problem with DevIL for years (including Muhammad Haggag in 2003). I'm surprised it hasn't been fixed yet.

Share this post


Link to post
Share on other sites
Quote:

Also, I don't want to use const char *'s so that I can just make one, and not have to make a new one every time I call LoadGLTexture (which I do once a frame), because it's my understanding that'll drastically slow my program down.


This hasn't got to do with your original question, but if you call LoadGLTexture() each frame you will have a slowdown, but you can be sure that copying a string won't be the cause of it.

Share this post


Link to post
Share on other sites
Quote:
Original post by Prototype
No, no, no. You should never cast away constness like that, even if you're 'sure' that your function never modifies the data. You are just undermining the security features of the language if you do that.


Yea, I know that. I guess I should have added a 'but don't do this' message.
Quote:
You shouldn't modify the data directly.

Oh wait, I did [razz]

Quote:
Original post by Prototype
If you really want to modify it, make a copy or else just have your function take a const char* as well.


Seems like I covered that as well.

And in the end, casting away constness was the answer [razz] (although using a C++ cast instead of a C cast.)

Share this post


Link to post
Share on other sites
Hello EmrldDrgn,

Actually it is very simple to do what you want. Just add one more line that makes use of a C Standard Library string copier function strcpy.

I did not see a declaration for ILholder in your original code so I added my own.

#include <cstring>


GLuint LoadGLTexture(std::string loader)
{
ilInit();
iluInit();
ilutRenderer(ILUT_OPENGL);
ilutInit();

loader = "Data/" + loader + ".bmp";
char* ILholder = new char[loader.length()];
texture = ilutGLLoadImage(strcpy(ILholder, loader.c_str());
delete []ILholder;

return texture;
}



strcpy is a function from the cstring header file. It basically does a copy from a char array to another char array. Its return value is the final char array pointer.

Hope this helps.

Regards,
Joshua

Share this post


Link to post
Share on other sites
Quote:
Original post by Hot Dog
Actually it is very simple to do what you want.

Simple you say? Well, you failed. Your temporary buffer, ILholder, is too short, so strcpy will write outside it. Since you said it was so simple, I leave it up to you to figure out why and how to solve it.

Share this post


Link to post
Share on other sites
Someone forgot the null terminator, well spotted!

Looks like making a non-const copy is the only correct way to solve this, although a bit of const correctness in the library would help!

Share this post


Link to post
Share on other sites
Copying a string for use in a caveman-era function, and wrapping a return value, in the non-caveman era:


std::string doCStuffWith(const std::string& s) {
int len = s.length() + 1; // null terminators, rah rah rah
std::vector<char> raw(len); // or is that "raw raw raw"?
const char* str = s.c_str();

std::copy(str, str + len, raw.begin()); // Just say no to strcpy, memcpy etc.
brokenCFunction(&(raw[0]));
// Assuming the C function modifies the input string and we want to return the
// modified version
return std::string(&(raw[0]));
// vector storage is guaranteed contiguous now.
// No cleanup needed - handled by vector destructor.
// The C function could still screw things up by trying to increase the length
// of the passed-in string, but then it's REALLY broken.
}

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
Copying a string for use in a caveman-era function, and wrapping a return value, in the non-caveman era:


std::string doCStuffWith(const std::string& s) {
int len = s.length() + 1; // null terminators, rah rah rah
std::vector<char> raw(len); // or is that "raw raw raw"?
const char* str = s.c_str();

std::copy(str, str + len, raw.begin()); // Just say no to strcpy, memcpy etc.
brokenCFunction(&(raw[0]));
// Assuming the C function modifies the input string and we want to return the
// modified version
return std::string(&(raw[0]));
// vector storage is guaranteed contiguous now.
// No cleanup needed - handled by vector destructor.
// The C function could still screw things up by trying to increase the length
// of the passed-in string, but then it's REALLY broken.
}

Is there a specific reason you didn't just do std::copy(s.begin(), s.end(), raw.begin()); and did away with str all together?

Another possibility is std::vector<char> raw(s.begin(), s.end()); raw.push_back('\0'); But that's a little wasteful.

CM

Share this post


Link to post
Share on other sites
Quote:
Original post by Conner McCloud
Quote:
Original post by Zahlman
Copying a string for use in a caveman-era function, and wrapping a return value, in the non-caveman era:


std::string doCStuffWith(const std::string& s) {
int len = s.length() + 1; // null terminators, rah rah rah
std::vector<char> raw(len); // or is that "raw raw raw"?
const char* str = s.c_str();

std::copy(str, str + len, raw.begin()); // Just say no to strcpy, memcpy etc.
brokenCFunction(&(raw[0]));
// Assuming the C function modifies the input string and we want to return the
// modified version
return std::string(&(raw[0]));
// vector storage is guaranteed contiguous now.
// No cleanup needed - handled by vector destructor.
// The C function could still screw things up by trying to increase the length
// of the passed-in string, but then it's REALLY broken.
}

Is there a specific reason you didn't just do std::copy(s.begin(), s.end(), raw.begin()); and did away with str all together?


In case .c_str() returns a different pointer value on subsequent calls (pointing to an identical const representation). Pretty far-fetched, I suppose :
Quote:

Another possibility is std::vector<char> raw(s.begin(), s.end()); raw.push_back('\0'); But that's a little wasteful.


Only wasteful if your implementation's initial capacity matches initial size exactly (While such a requirement may exist, I'm not aware of it). :) That's quite elegant, though. Doh on me.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman

// vector storage is guaranteed contiguous now.



How is that guarenteed? Does this not depend on the implimentation of vector?
Or do I missunderstand how you can use vectors?

It just looks like this bypasses the vector interface, which is not very OO at all.
In this case, the library uses a depreciated type, so wouldnt it be appropriate to us the standard libraries designed for the job? ie strcpy?

Share this post


Link to post
Share on other sites
Quote:
Original post by MikeAinsworth
How is that guarenteed?

By ISO/IEC 14882:2003 Section 23.2.4 paragraph 1: "The elements of a vector are store contiguously...."

Share this post


Link to post
Share on other sites
Quote:
Original post by MikeAinsworth
Quote:
Original post by Zahlman

// vector storage is guaranteed contiguous now.



How is that guarenteed? Does this not depend on the implimentation of vector?
Or do I missunderstand how you can use vectors?



Par of std::vectors specification is that it holds elements contiguously.

Quote:

It just looks like this bypasses the vector interface, which is not very OO at all.


But the original problem is a workaround for a broken c interface. Not much that OO can do at all in that situation, std::string would perform admirably if it weren't for that.

Quote:

In this case, the library uses a depreciated type, so wouldnt it be appropriate to us the standard libraries designed for the job? ie strcpy?


strcpy() to what? A manually managed memory buffer? How is that more appropriate than using the c++ standard's buffer type, std::vector?

Share this post


Link to post
Share on other sites
All fair points Zahlman. I didn't intend that as an argumentative reply, but I'm a stickler for detail and I don't like using solutions that havent been thought through properly.

The advantage this gives you is a nicely C++ managed container rather than messing about with new and delete. Which now that you point it out is considerable more OO friendly.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement