105

I'm trying to convert std::string to float/double. I tried:

std::string num = "0.6";
double temp = (double)atof(num.c_str());

But it always returns zero. Any other ways?

herohuyongtao
  • 45,575
  • 23
  • 118
  • 159
Max Frai
  • 52,556
  • 73
  • 182
  • 293

16 Answers16

131
std::string num = "0.6";
double temp = ::atof(num.c_str());

Does it for me, it is a valid C++ syntax to convert a string to a double.

You can do it with the stringstream or boost::lexical_cast but those come with a performance penalty.


Ahaha you have a Qt project ...

QString winOpacity("0.6");
double temp = winOpacity.toDouble();

Extra note:
If the input data is a const char*, QByteArray::toDouble will be faster.

TimW
  • 8,075
  • 1
  • 27
  • 32
  • I don't see any reason why boost::lexical_cast would have a performance penalty (but a stringstream is certainly slower). – Zifre Jun 18 '09 at 13:33
  • 7
    boost::lexical_cast is streaming. – TimW Jun 18 '09 at 13:40
  • 1
    You can't generally say they come with a performance penalty, i think. Think about what happens when just before it you have a cin >> num;. The user would have to type very quickly (rly jon skeet like) to ever note the milliseconds lexical_cast is slower :) That said, i believe there are tasks where lexical_cast just sucks too much performance :) – Johannes Schaub - litb Jun 18 '09 at 13:42
  • ... there is always a performance penalty, this penalty can be significant or not for the performance of the application. If the user can type very very very quickly it will be significant ;) – TimW Jun 18 '09 at 13:48
  • Thanks... I needn't in Boost. And i've forgot about Qt :D. – Max Frai Jun 18 '09 at 14:02
  • 3
    For this solution, what does the :: in front of atof() do? What does it need to be there? – sivabudh Feb 17 '10 at 02:04
  • 4
    @ShaChris Because I want to make sure I use the atof function from the global namespace. – TimW Feb 17 '10 at 08:16
  • Do you have an alternative for `string` to `float` that doesn't use `stof` (which only comes with new C++11) – user13107 Sep 23 '13 at 08:18
  • strtod() is better if you're worried about bad values. Also, both of these won't throw exceptions, which is great. – Jason Doucette Feb 12 '15 at 23:30
  • 1
    depends on the current locale – nmr Jan 20 '17 at 21:49
  • Why is the scope resolution operator used here? `::atof(num.c_str());` – Nubcake Oct 12 '17 at 19:00
109

The Standard Library (C++11) offers the desired functionality with std::stod :

std::string  s  = "0.6"
std::wstring ws = "0.7"
double d  = std::stod(s);
double dw = std::stod(ws);

Generally for most other basic types, see <string>. There are some new features for C strings, too. See <stdlib.h>

ManuelSchneid3r
  • 14,156
  • 9
  • 53
  • 94
29

Lexical cast is very nice.

#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>

using std::endl;
using std::cout;
using std::string;
using boost::lexical_cast;

int main() {
    string str = "0.6";
    double dub = lexical_cast<double>(str);
    cout << dub << endl;
}
Bill Lynch
  • 72,481
  • 14
  • 116
  • 162
  • Thanks, it works.. But it's a question for me: why my code isn't working. – Max Frai Jun 18 '09 at 13:55
  • 2
    @Johannes Schaub: Based on ADL, he might as well have, the using defintions plus what he is actually using will probably bring into scope a vast number of std elements. Furthermore lexical_cast is insanely slow, so no +1 from me. –  Mar 10 '11 at 17:15
  • A nice feature of boost::lexical_cast is the error handling. If a conversion fails, an exception is thrown: `try { ... boost::lexical_cast ... } catch (std::exception const& err) { //handle excpetion }` – Semjon Mössinger May 09 '16 at 13:50
  • To be more precise, use `catch ( boost::bad_lexical_cast const& err )` to catch the exception. – Semjon Mössinger May 09 '16 at 14:56
14

You can use std::stringstream:

   #include <sstream>
   #include <string>
   template<typename T>
   T StringToNumber(const std::string& numberAsString)
   {
      T valor;

      std::stringstream stream(numberAsString);
      stream >> valor;
      if (stream.fail()) {
         std::runtime_error e(numberAsString);
         throw e;
      }
      return valor;
   }

Usage:

double number= StringToNumber<double>("0.6");
Edison Gustavo Muenz
  • 8,202
  • 6
  • 35
  • 41
  • Uhm, so you think boost::lexical_cast has a terrible interface, don't you? Look at stefanB's answer! Boost does the same. – kirsche40 Feb 21 '14 at 14:38
  • @kirsche40 Seems like a good alternative for people that don't already have dependencies with Boost (linking with Boost only to convert a std::string to numbers is a bit overkill !) – Jean-Philippe Jodoin Jul 22 '14 at 17:40
  • @JEan-Phillippe Jodiun I answered to a now deleted comment, where someone recommended Boost. I am aware that Boost is most of the time overkill. By the way, for some time now usage of Boost is restricted to "newer" compilers. Older projects cannot use Boost. For example ASIO depends heavy on C++11-features like std::addressof which makes it completely worthless for C++98/C++03 compilers. IMHO, when the project started it was the intention of Boost to provide new "standardized" features for older compiler versions... :-( – kirsche40 Jul 23 '14 at 14:31
10

Yes, with a lexical cast. Use a stringstream and the << operator, or use Boost, they've already implemented it.

Your own version could look like:

template<typename to, typename from>to lexical_cast(from const &x) {
  std::stringstream os;
  to ret;

  os << x;
  os >> ret;

  return ret;  
}
DaClown
  • 3,461
  • 5
  • 26
  • 30
7

You can use boost lexical cast:

#include <boost/lexical_cast.hpp>

string v("0.6");
double dd = boost::lexical_cast<double>(v);
cout << dd << endl;

Note: boost::lexical_cast throws exception so you should be prepared to deal with it when you pass invalid value, try passing string("xxx")

stefanB
  • 69,149
  • 26
  • 113
  • 140
6

If you don't want to drag in all of boost, go with strtod(3) from <cstdlib> - it already returns a double.

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>

using namespace std;

int main()  {
    std::string  num = "0.6";
    double temp = ::strtod(num.c_str(), 0);

    cout << num << " " << temp << endl;
    return 0;
}

Outputs:

$ g++ -o s s.cc
$ ./s
0.6 0.6
$

Why atof() doesn't work ... what platform/compiler are you on?

Bill Lynch
  • 72,481
  • 14
  • 116
  • 162
haavee
  • 4,111
  • 19
  • 21
3

I had the same problem in Linux

double s2f(string str)
{
 istringstream buffer(str);
 double temp;
 buffer >> temp;
 return temp;
}

it works.

kenn
  • 319
  • 12
  • 22
2
   double myAtof ( string &num){
      double tmp;
      sscanf ( num.c_str(), "%lf" , &tmp);
      return tmp;
   }
dpetek
  • 655
  • 1
  • 5
  • 11
  • 2
    Invalid answer, how do you know the value stored in num is actually a valid floating point number? you don't check the return type of sscanf, seems like an MS coding style. –  Mar 10 '11 at 17:19
1

As to why atof() isn't working in the original question: the fact that it's cast to double makes me suspicious. The code shouldn't compile without #include <stdlib.h>, but if the cast was added to solve a compile warning, then atof() is not correctly declared. If the compiler assumes atof() returns an int, casting it will solve the conversion warning, but it will not cause the return value to be recognized as a double.

#include <stdlib.h>
#include <string>

... 
  std::string num = "0.6";
  double temp = atof(num.c_str());

should work without warnings.

Iain
  • 11
  • 2
1

This answer is backing up litb in your comments. I have profound suspicions you are just not displaying the result properly.

I had the exact same thing happen to me once. I spent a whole day trying to figure out why I was getting a bad value into a 64-bit int, only to discover that printf was ignoring the second byte. You can't just pass a 64-bit value into printf like its an int.

T.E.D.
  • 41,324
  • 8
  • 64
  • 131
  • I'm not using printf to see results... And i use that value to set window opacity, and my window is full trasparent, so value is 0. – Max Frai Jun 18 '09 at 13:54
1

The C++ 11 way is to use std::stod and std::to_string. Both work in Visual Studio 11.

BSalita
  • 6,917
  • 5
  • 48
  • 60
0

Rather than dragging Boost into the equation, you could keep your string (temporarily) as a char[] and use sprintf().

But of course if you're using Boost anyway, it's really not too much of an issue.

kba
  • 18,696
  • 5
  • 56
  • 84
Chris Tonkinson
  • 12,213
  • 12
  • 52
  • 87
0

You don't want Boost lexical_cast for string <-> floating point anyway. That subset of use cases is the only set for which boost consistently is worse than the older functions- and they basically concentrated all their failure there, because their own performance results show a 20-25X SLOWER performance than using sscanf and printf for such conversions.

Google it yourself. boost::lexical_cast can handle something like 50 conversions and if you exclude the ones involving floating point #s its as good or better as the obvious alternatives (with the added advantage of being having a single API for all those operations). But bring in floats and its like the Titanic hitting an iceberg in terms of performance.

The old, dedicated str->double functions can all do 10000 parses in something like 30 ms (or better). lexical_cast takes something like 650 ms to do the same job.

Zack Yezek
  • 1,234
  • 14
  • 5
  • No source? I googled it myself: http://www.boost.org/doc/libs/1_55_0/doc/html/boost_lexical_cast/performance.html – Blake Oct 29 '14 at 15:20
0

My Problem:

  1. Locale independent string to double (decimal separator always '.')
  2. Error detection if string conversion fails

My solution (uses the Windows function _wcstod_l):

// string to convert. Note: decimal seperator is ',' here
std::wstring str = L"1,101";

// Use this for error detection
wchar_t* stopString;

// Create a locale for "C". Thus a '.' is expected as decimal separator
double dbl = _wcstod_l(str.c_str(), &stopString, _create_locale(LC_ALL, "C")); 

if (wcslen(stopString) != 0)
{
    // ... error handling ... we'll run into this because of the separator
}

HTH ... took me pretty long to get to this solution. And I still have the feeling that I don't know enough about string localization and stuff...

anhoppe
  • 3,441
  • 3
  • 41
  • 53
0

With C++17, you can use std::from_chars, which is a lighter weight faster alternative to std::stof and std::stod. It doesn't involve any memory allocation or look at the locale, and it is non-throwing.

The std::from_chars function returns a value of type from_chars_result, which is basically a struct with two fields:

struct from_chars_result {
    const char* ptr;
    std::errc ec;
};

By inspecting ec we can tell if the conversion was successful:

#include <iostream>
#include <charconv>

int main()
{
    const std::string str { "12345678901234.123456" };
    double value = 0.0;
    auto [p, ec] = std::from_chars(str.data(), str.data() + str.size(), value);
    if (ec != std::errc()) {
        std::cout << "Couldn't convert value";
    }
    
    return 0;
}
jignatius
  • 5,606
  • 2
  • 7
  • 21