如何在C ++中将数字转换为字符串,反之亦然


120

由于这个问题每周都会被问到,因此该常见问题解答可能会对很多用户有所帮助。

  • 如何在C ++中将整数转换为字符串

  • 如何在C ++中将字符串转换为整数

  • 如何在C ++中将浮点数转换为字符串

  • 如何在C ++中将字符串转换为浮点数


对于此类转换,我有一个书签converttypes.com
Firzok Nadeem

Answers:


129

C ++ 11更新

根据C++11标准,字符串到数字的转换以及反之亦然已内置到标准库中。包含以下所有功能<string>(根据第21.5节)。

字符串到数字

float              stof(const string& str, size_t *idx = 0);
double             stod(const string& str, size_t *idx = 0);
long double        stold(const string& str, size_t *idx = 0);
int                stoi(const string& str, size_t *idx = 0, int base = 10);
long               stol(const string& str, size_t *idx = 0, int base = 10);
unsigned long      stoul(const string& str, size_t *idx = 0, int base = 10);
long long          stoll(const string& str, size_t *idx = 0, int base = 10);
unsigned long long stoull(const string& str, size_t *idx = 0, int base = 10);

它们中的每一个都将字符串作为输入,并将尝试将其转换为数字。如果无法构造有效的数字,例如因为没有数字数据或该数字超出该类型的范围,则会引发异常(std::invalid_argumentstd::out_of_range)。

如果转换成功而idx不是0idx则将包含未用于解码的第一个字符的索引。这可能是最后一个字符后面的索引。

最后,整数类型允许指定一个底数,对于大于9的数字,假定为字母(a=10直到z=35)。您可以在此处找到有关可以解析为浮点数,带符号整数无符号整数的确切格式的更多信息。

最后,对于每个函数,还有一个接受a std::wstring作为其第一个参数的重载。

数字到字符串

string to_string(int val);
string to_string(unsigned val);
string to_string(long val);
string to_string(unsigned long val);
string to_string(long long val);
string to_string(unsigned long long val);
string to_string(float val);
string to_string(double val);
string to_string(long double val);

这些更为简单,您传递适当的数字类型,然后返回字符串。对于格式选项,您应该返回C ++ 03 stringsream选项并使用流操纵器,如此处其他答案所述。

如注释中所述,这些函数将恢复为默认的尾数精度,该精度可能不是最大精度。如果您的应用程序需要更高的精度,那么最好也返回其他字符串格式设置过程。

还定义了类似的函数to_wstring,它们将返回std::wstring


3
std::to_string浮点类型失去很多精度。例如,double f = 23.4323897462387526; std::string f_str = std::to_string(f);返回一个字符串23.432390。这使得使用这些功能无法往返浮点数。
fun4jimmy 2014年

@ fun4jimmy这是标准或实现特定的限制吗?将其添加到答案。在字符串中往返浮动并不是一个好主意。
KillianDS 2014年

C ++标准说“ 返回:每个函数返回字符串对象保持,将通过调用来产生其自变量的值的字符表示sprintf(buf, fmt, val)与的格式指定符‘%d’‘%U’‘%LD’” %录“ ”%LLD“ , ”%LLU“ ”%F“ ”%F“ ,或”%LF“表示,其中buf指定具有足够的尺寸的内部字符缓冲区。 ”我有一个看看C99标准的printf,我认为小数位的数量依赖于#define DECIMAL_DIGfloat.h
fun4jimmy 2014年

布鲁斯•道森(Bruce Dawson)在他的博客上有一些不错的文章,关于往返浮点数需要多少精度。
fun4jimmy 2014年

2
所有这些功能均受全局语言环境的影响,如果您使用库,尤其是使用线程,可能会导致问题。在这里看到我的问题:stackoverflow.com/questions/31977457/…–
同一时间

86

如何在C ++ 03中将数字转换为字符串

  1. 不要使用itoa还是itof因为他们是非标准的,因此不便于携带的功能。
  2. 使用字符串流

     #include <sstream>  //include this to use string streams
     #include <string> 
    
    int main()
    {    
        int number = 1234;
    
        std::ostringstream ostr; //output string stream
        ostr << number; //use the string stream just like cout,
        //except the stream prints not to stdout but to a string.
    
        std::string theNumberString = ostr.str(); //the str() function of the stream 
        //returns the string.
    
        //now  theNumberString is "1234"  
    }

    请注意,您也可以使用字符串流将浮点数转换为字符串,并根据需要格式化字符串,就像使用 cout

    std::ostringstream ostr;
    float f = 1.2;
    int i = 3;
    ostr << f << " + " i << " = " << f + i;   
    std::string s = ostr.str();
    //now s is "1.2 + 3 = 4.2" 

    您可以使用流操纵等std::endlstd::hex以及功能std::setw()std::setprecision()等用绳子流在完全相同的方式与相同cout

    不要 std::ostringstream混淆std::ostrstream。后者已弃用

  3. 使用boost词法转换。如果您不熟悉boost,那么最好从lexical_cast这样的小型库开始。要下载并安装boost及其文档,请转到此处。尽管boost不是C ++标准,但许多boost库最终都已标准化,并且boost被认为是最好的C ++库。

    词法转换使用下面的流,因此基本上此选项与前一个相同,只是比较冗长。

    #include <boost/lexical_cast.hpp>
    #include <string>
    
    int main()
    {
       float f = 1.2;
       int i = 42;
       std::string sf = boost::lexical_cast<std::string>(f); //sf is "1.2"
       std::string si = boost::lexical_cast<std::string>(i); //sf is "42"
    }

如何在C ++ 03中将字符串转换为数字

  1. 从C继承的最轻量级的选项是函数atoi(对于整数(从字母到整数))和atof(对于浮点值(从字母到浮点))。这些函数将C样式的字符串作为参数(const char *),因此,它们的使用可能不被视为完全正确的C ++实践。cplusplus.com上有关于atoiatof的易于理解的文档,包括输入错误时的行为。但是,该链接包含一个错误,根据标准,如果输入数字太大而无法容纳目标类型,则行为是不确定的。

    #include <cstdlib> //the standard C library header
    #include <string>
    int main()
    {
        std::string si = "12";
        std::string sf = "1.2";
        int i = atoi(si.c_str()); //the c_str() function "converts" 
        double f = atof(sf.c_str()); //std::string to const char*
    }
  2. 使用字符串流(这次输入字符串流istringstream)。同样,使用istringstream就像一样cin。再次,不要istringstream与混淆istrstream。后者已弃用。

    #include <sstream>
    #include <string>
    int main()
    {
       std::string inputString = "1234 12.3 44";
       std::istringstream istr(inputString);
       int i1, i2;
       float f;
       istr >> i1 >> f >> i2;
       //i1 is 1234, f is 12.3, i2 is 44  
    }
  3. 使用boost词法转换

    #include <boost/lexical_cast.hpp>
    #include <string>
    
    int main()
    {
       std::string sf = "42.2"; 
       std::string si = "42";
       float f = boost::lexical_cast<float>(sf); //f is 42.2
       int i = boost::lexical_cast<int>(si);  //i is 42
    }       

    如果输入错误,则lexical_cast抛出type异常boost::bad_lexical_cast


4
的cplusplus文档atoi不是很好,这是不正确的。它没有提到如果字符串的数字值不能用表示int,则该行为是不确定的。它说的是,超出范围的值固定在INT_MAX/ INT_MIN,我在C ++ 03或C89中都找不到。对于不受信任/未经验证的输入,或者在处理流不支持的基础时,需要使用strtol,它已定义了错误行为。和atof/ 类似的评论strtod
史蒂夫·杰索普

2
cplusplus.com关于“ atoi”是错误的。它说关于返回值“如果不能执行有效的转换,则返回零值。如果正确的值超出可表示的值的范围,则返回INT_MAX或INT_MIN。”,但规范说“如果结果的值无法表示,行为未定义。” “除错误行为外,它们等效于(int)strtol(nptr, (char **)NULL, 10)。atoi [...]函数返回转换后的值。” 对于初学者而言,cplusplus.com被认为是令人难以置信的糟糕信息来源。
Johannes Schaub-litb 2011年

istr >> i1 >> f >> i2;严重错过了成功的检查。
2011年

4
可能要添加std::to_string
Pubby

1
@ArmenTsirunyan:+10,这是我见过的最好的答案之一。感谢您的回答。
Abhineet 2012年

4

在C ++ 17,新的功能的std :: to_chars标准:: from_chars在报头被引入的Charconv

std :: to_chars是与语言环境无关,不分配且不抛出异常的。

仅提供其他库使用的格式化策略的一小部分(例如std :: sprintf)。

std :: to_chars,与std :: from_chars相同。

只有两个函数都来自同一实现,才能保证std :: from_chars可以完全恢复由to_chars格式化的每个浮点值。

 // See en.cppreference.com for more information, including format control.
#include <cstdio>
#include <cstddef>
#include <cstdlib>
#include <cassert>
#include <charconv>

using Type =  /* Any fundamental type */ ;
std::size_t buffer_size = /* ... */ ;

[[noreturn]] void report_and_exit(int ret, const char *output) noexcept 
{
    std::printf("%s\n", output);
    std::exit(ret);
}
void check(const std::errc &ec) noexcept
{
    if (ec ==  std::errc::value_too_large)
        report_and_exit(1, "Failed");
}
int main() {
    char buffer[buffer_size];        
    Type val_to_be_converted, result_of_converted_back;

    auto result1 = std::to_chars(buffer, buffer + buffer_size,  val_to_be_converted);
    check(result1.ec);
    *result1.ptr = '\0';

    auto result2 = std::from_chars(buffer, result1.ptr, result_of_converted_back);
    check(result2.ec);

    assert(val_to_be_converted == result_of_converted_back);
    report_and_exit(0, buffer);
}

尽管编译器尚未完全实现它,但肯定会实现。


0

我从StackOverflow的某个地方偷走了这个便捷类,将任何可流式转换为字符串:

// make_string
class make_string {
public:
  template <typename T>
  make_string& operator<<( T const & val ) {
    buffer_ << val;
    return *this;
  }
  operator std::string() const {
    return buffer_.str();
  }
private:
  std::ostringstream buffer_;
};

然后将其用作;

string str = make_string() << 6 << 8 << "hello";

很漂亮!

此外,如果您尝试解析不包含数字的字符串,我也使用此函数将字符串转换为任何可流式传输的内容,尽管这样做并不安全。 (它也不如最后一个那么聪明)

// parse_string
template <typename RETURN_TYPE, typename STRING_TYPE>
RETURN_TYPE parse_string(const STRING_TYPE& str) {
  std::stringstream buf;
  buf << str;
  RETURN_TYPE val;
  buf >> val;
  return val;
}

用于:

int x = parse_string<int>("78");

您可能还需要wstrings的版本。


5
这正是boost :: lexical_cast所做的。而Boost则以一种更为通用的方式来做到这一点。
Armen Tsirunyan 2011年

是的,我略过了第一个答案,却没有看到boost :: lexical_casts。
维克多·塞尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.