Convert string to float (not quite typical! =) - solved
Blah blah asked a million times.
Anyways, I'm making a level loading system and need to load in some floating point numbers from a text file. A 3D vertex coordinate is stored like this in the file:
[0 0 0]
I've been using sprintf to convert it to 3 floating point errors, or trying to. The code looks like this, where "c" is a pointer to the character array of the vertex (it has the proper values - I checked):
//c is created as a new character array on the heap, given the string loaded from
//the file.
sprintf(c, "[%f %f %f]", vertex.x, vertex.y, vertex.z);
delete [] c;
However, when I call delete on "c", the program segfaults and crashes. I checked the value of "c" in the debugger, and it changes like this:
Loaded from file:
[0 0 0]
After sprintf:
[0.000000 0.000000 0.000000]
So when I call delete on it, the program crashes. I'm thinking that I would like a different method to convert "c" to a set of floating points in a similar manner to what I'm doing above. However, I would also like to avoid crashing the program. Any hints? Thanks!
[Edited by - silverphyre673 on November 26, 2005 2:21:36 PM]
Some possible reasons:
_ You mixed malloc () with delete
_ The allocated memory is not large enough for sprintf ()
_ Mistakes in calling new [] (I don't know for sure, please post your code)
_ The program stack segment is probably broken before sprintf () is executed, sprintf and c are just victims[smile].
sprintf () requires a char * pointer to be passed but it doesn't matter what is your real pointer type, just provide a cast for sprintf () and the compiler will silently compile your code.
Unless you intented to do something with c after used it to store floating point values, it's best to declare c as float * .
[Edit]
Are vertex.[x/y/z] 3 chars ?
What is the purpose of '[' and ']' in
_ You mixed malloc () with delete
_ The allocated memory is not large enough for sprintf ()
_ Mistakes in calling new [] (I don't know for sure, please post your code)
_ The program stack segment is probably broken before sprintf () is executed, sprintf and c are just victims[smile].
sprintf () requires a char * pointer to be passed but it doesn't matter what is your real pointer type, just provide a cast for sprintf () and the compiler will silently compile your code.
Unless you intented to do something with c after used it to store floating point values, it's best to declare c as float * .
[Edit]
Are vertex.[x/y/z] 3 chars ?
What is the purpose of '[' and ']' in
sprintf(c, "[%f %f %f]", vertex.x, vertex.y, vertex.z);
I don't see how you're loading and not saving - you have a char array containing vertices and you want to load it into vertex.[xyz], correct? Then you want to use sscanf, not sprintf. Or better yet, a stringstream. If you really do want to put the vertices into c, then continue reading below.
First - make sure that vertex.[xyz] are all floats and not some other data type. (unlikely, but with printf you just have to be sure)
Second - I would be leery of using sprintf. If you're using C++ (which you are - you have delete[]) then use a stringstream. Just create a new stringstream, do << "[ " << vertex.x << " " << vertex.y and so on. Then you can grab a string out of it using >> (some string) and doing .c_str() on the string. If you have a preexisting char array you can then do a strncpy to it.
If you must use sprintf, use snprintf instead (it's called something like _snprintf on msvc) That way if you are accidentally overwriting your buffer then you will get an incomplete string instead of a blown away stack.
First - make sure that vertex.[xyz] are all floats and not some other data type. (unlikely, but with printf you just have to be sure)
Second - I would be leery of using sprintf. If you're using C++ (which you are - you have delete[]) then use a stringstream. Just create a new stringstream, do << "[ " << vertex.x << " " << vertex.y and so on. Then you can grab a string out of it using >> (some string) and doing .c_str() on the string. If you have a preexisting char array you can then do a strncpy to it.
If you must use sprintf, use snprintf instead (it's called something like _snprintf on msvc) That way if you are accidentally overwriting your buffer then you will get an incomplete string instead of a blown away stack.
You've confused sprintf with sscanf. Try the following:
sscanf (c, "[%f %f %f]", &vertex.x, &vertex.y, &vertex.z);
I'm using C++, not C, and I might have gotten you, or you gotten me, confused between the variable "c" and the language =)
Anyways, I won't post my loading code, but suffice to say that the vertex coordinates are stored in the text file between brackets for readability. So if you were going to store a vertex, you would store it like this:
[0 15 3]
It is loaded into an std::string buffer, and I do this to store the string in a char *, so I can use it with sprintf:
EDIT:
Ah, yes... I do want to put the string values into the float... Oops! Thanks!
Anyways, I won't post my loading code, but suffice to say that the vertex coordinates are stored in the text file between brackets for readability. So if you were going to store a vertex, you would store it like this:
[0 15 3]
It is loaded into an std::string buffer, and I do this to store the string in a char *, so I can use it with sprintf:
struct Vertex{ float x, y, z;};//...//In loading function:Vertex vertex;std::string buffer = GetVertex(); //Load vertex value from text file, storechar * temp = new char[buffer.length() + 1]; //For sprintfstd::strcpy(temp, buffer.c_str()); //Copy string stored in "buffer" into "temp"//temp now has the value "[0 15 3]"sprintf(temp, "[%f %f %f]", vertex.x, vertex.y, vertex.z);delete [] temp; //Program actually crashes on this line, but value of temp appears to change on the last line.
EDIT:
Ah, yes... I do want to put the string values into the float... Oops! Thanks!
std::stringstream s << GetVertex();s >> std::ws;char p= s.peek();if(p != '[') std::error();s.ignore();s >> vertex.x >> vertex.y >> vertex.z;s >> std::ws;p= s.peek();if(p != ']') std::error();//done
not tested, but you get the idea... boost has such stuff already in function form, but i dont use boost frequently enough to tell you the functionnames
and now: pls stop using c functions ;)
T2k
Actually, say what you want about type safety BUT:
1) C functions can be largely checked for type safety by the compiler.
2) C functions are significantly faster - not like twice as fast but orders of magnitude
3) C functions are simpler to use (if you know the formatting commands); why do you think they made boost::format? (which by the way, is still slow)
1) C functions can be largely checked for type safety by the compiler.
2) C functions are significantly faster - not like twice as fast but orders of magnitude
3) C functions are simpler to use (if you know the formatting commands); why do you think they made boost::format? (which by the way, is still slow)
Quote:Original post by Puzzler183
Actually, say what you want about type safety BUT:
1) C functions can be largely checked for type safety by the compiler.
void* and varargs, which C uses all over the place, are the anitithesis of type safety. In most cases they cannot be checked by the compiler, although in a few instances it's possible. Not to mention that printf has it's own vulnerability named after it. There's a reason you get "printf format string vulnerabilty" but never "iostream manipulater vulnerability".
Quote:Original post by Puzzler183
2) C functions are significantly faster - not like twice as fast but orders of magnitude
That has nothing to do with them being "C" functions, it's just because they're either less safe, less general, or less extensible.
The String Formatters of Manor Farm by Herb Sutter
Quote:Original post by Puzzler183
3) C functions are simpler to use (if you know the formatting commands); why do you think they made boost::format? (which by the way, is still slow)
No, C functions have more succinct operations for formatting. However, they are still resticted to built-in types, so are not simpler to use with custom data types:
Vector3D v( 3, 4, 5 );
printf( "%?", v ); // uhoh. Dies no matter what you put for ?
cout << v; // works fine
cout << boost::format( "%+05s" ) % v; // also works fine
Also, c-style I/O can only be used for the limited cases that it allows for. In C++, you can have cout write zlib-compressed data with just:
zlib_ostreambuf<char> zsb( cout.rdbuf() );
cout.rdbuf( zsb );
And then using cout as you normally would.
Quote:Original post by me22Really? GCC's format string validator works great, except perphaps for dynamic formats (but such things are very rare, and there's no equivalent functionality in standard C++ library).
In most cases they cannot be checked by the compiler, although in a few instances it's possible. Not to mention that printf has it's own vulnerability named after it.
Just don't forget to mark your functions as such when making a printf wrapper.
Quote:Original post by doynaxChecking the %? parts of the string passed to printf is only a weak compiler extension. Without having actually used it, I assume it wont work when your format string isn't a constant string, written directly into the function call, but is stored in some variable instead.Quote:Original post by me22Really? GCC's format string validator works great, except perphaps for dynamic formats (but such things are very rare, and there's no equivalent functionality in standard C++ library).
In most cases they cannot be checked by the compiler, although in a few instances it's possible. Not to mention that printf has it's own vulnerability named after it.
Just don't forget to mark your functions as such when making a printf wrapper.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement