Cách chuyển một số thành chuỗi và ngược lại trong C ++


120

Vì câu hỏi này được hỏi hàng tuần nên Câu hỏi thường gặp này có thể giúp ích rất nhiều cho người dùng.

  • Cách chuyển đổi một số nguyên thành một chuỗi trong C ++

  • cách chuyển đổi một chuỗi thành một số nguyên trong C ++

  • cách chuyển đổi một số dấu phẩy động thành một chuỗi trong C ++

  • cách chuyển đổi một chuỗi thành một số dấu phẩy động trong C ++


Để chuyển đổi như vậy, tôi có một dấu trang converttypes.com
Firzok Nadeem.

Câu trả lời:


129

Cập nhật cho C ++ 11

Theo C++11tiêu chuẩn, chuyển đổi chuỗi thành số và ngược lại được tích hợp sẵn trong thư viện tiêu chuẩn. Tất cả các chức năng sau đây đều có trong <string>(theo đoạn 21.5).

chuỗi thành số

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);

Mỗi trong số này lấy một chuỗi làm đầu vào và sẽ cố gắng chuyển đổi nó thành một số. Nếu không có số hợp lệ nào có thể được tạo, chẳng hạn như vì không có dữ liệu số hoặc số nằm ngoài phạm vi cho loại, một ngoại lệ sẽ được đưa ra ( std::invalid_argumenthoặc std::out_of_range).

Nếu chuyển đổi thành công và idxkhông thành công 0, idxsẽ chứa chỉ mục của ký tự đầu tiên không được sử dụng để giải mã. Đây có thể là một chỉ mục đằng sau ký tự cuối cùng.

Cuối cùng, các kiểu tích phân cho phép xác định một cơ số, đối với các chữ số lớn hơn 9, bảng chữ cái được giả định ( a=10cho đến khi z=35). Bạn có thể tìm thêm thông tin về định dạng chính xác có thể phân tích cú pháp tại đây cho số dấu phẩy động , số nguyên có dấusố nguyên không dấu .

Cuối cùng, đối với mỗi hàm cũng có một quá tải chấp nhận a std::wstringlà tham số đầu tiên.

số thành chuỗi

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);

Những điều này đơn giản hơn, bạn chuyển kiểu số thích hợp và bạn nhận lại một chuỗi. Đối với các tùy chọn định dạng, bạn nên quay lại tùy chọn dòng chuỗi C ++ 03 và sử dụng trình điều khiển dòng, như được giải thích trong một câu trả lời khác ở đây.

Như đã lưu ý trong các nhận xét, các hàm này trở lại độ chính xác phần định trị mặc định có thể không phải là độ chính xác tối đa. Nếu ứng dụng của bạn cần độ chính xác cao hơn, tốt nhất bạn nên quay lại các quy trình định dạng chuỗi khác.

Ngoài ra còn có các hàm tương tự được định nghĩa được đặt tên to_wstring, các hàm này sẽ trả về a std::wstring.


3
std::to_stringmất nhiều độ chính xác đối với các loại dấu phẩy động. Ví dụ: double f = 23.4323897462387526; std::string f_str = std::to_string(f);trả về một chuỗi 23.432390. Điều này làm cho không thể làm tròn các giá trị dấu chấm động bằng cách sử dụng các hàm này.
fun4jimmy

@ fun4jimmy đây có phải là hạn chế được áp đặt bởi tiêu chuẩn hoặc triển khai cụ thể không? Sẽ thêm nó vào câu trả lời. Không phải việc trượt vòng trôi qua dây là một ý tưởng hay.
KillianDS

Các C ++ chuẩn nói " Returns: Mỗi hàm trả về một đối tượng chuỗi giữ đại diện đặc trưng của giá trị của đối số của nó mà có thể được tạo ra bởi sự kêu gọisprintf(buf, fmt, val) với một specifier dạng của '% d' , '% u' , '% ld' , " % lu " , "% lld " , "% llu " , "% f " , "% f " hoặc "% Lf " tương ứng, trong đó bufchỉ định một bộ đệm ký tự bên trong có đủ kích thước. "Tôi đã xem xét tiêu chuẩn C99 cho printf và tôi nghĩ rằng số vị trí thập phân phụ thuộc vào#define DECIMAL_DIG trongfloat.h.
fun4jimmy

Bruce Dawson có một số bài viết hay về độ chính xác cần thiết cho các số dấu phẩy động trượt tròn trên blog của anh ấy .
fun4jimmy

2
Tất cả các chức năng này đều bị ảnh hưởng bởi ngôn ngữ chung, điều này có thể dẫn đến sự cố nếu bạn sử dụng thư viện và đặc biệt là nếu sử dụng chuỗi. Xem câu hỏi của tôi tại đây: stackoverflow.com/questions/31977457/…
Ident

86

Làm thế nào để chuyển đổi một số thành một chuỗi trong C ++ 03

  1. Không sử dụng cácitoahoặcitofchức năng, vì họ là phi tiêu chuẩn và do đó không cầm tay.
  2. Sử dụng các luồng chuỗi

     #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"  
    }

    Lưu ý rằng bạn cũng có thể sử dụng các luồng chuỗi để chuyển đổi số dấu phẩy động thành chuỗi và cũng để định dạng chuỗi theo ý muốn, giống như với 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" 

    Bạn có thể sử dụng thao tác dòng, chẳng hạn như std::endl, std::hexvà chức năng std::setw(), std::setprecision()vv với những con suối trong chuỗi chính xác theo cách tương tự như vớicout

    Đừng nhầm lẫn std::ostringstream vớistd::ostrstream. Cái sau không được dùng nữa

  3. Sử dụng tăng từ vựng . Nếu bạn không quen với boost, bạn nên bắt đầu với một thư viện nhỏ như lexical_cast này. Để tải xuống và cài đặt boost và tài liệu của nó, hãy truy cập vào đây . Mặc dù boost không có trong tiêu chuẩn C ++, nhưng cuối cùng thì thư viện boost cũng được chuẩn hóa và boost được nhiều người coi là thư viện C ++ tốt nhất.

    Lexical cast sử dụng các luồng bên dưới, vì vậy về cơ bản tùy chọn này giống với tùy chọn trước đó, chỉ ít dài dòng hơn.

    #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"
    }

Làm thế nào để chuyển đổi một chuỗi thành một số trong C ++ 03

  1. Tùy chọn nhẹ nhất, kế thừa từ C, là các hàm atoi(đối với số nguyên (theo thứ tự bảng chữ cái sang số nguyên)) và atof(đối với các giá trị dấu phẩy động (từ bảng chữ cái đến số thực)). Các hàm này lấy một chuỗi kiểu C làm đối số ( const char *) và do đó việc sử dụng chúng có thể được coi là một cách thực hành C ++ không chính xác. cplusplus.com có ​​tài liệu dễ hiểu về cả hai atoiatof, bao gồm cách chúng hoạt động trong trường hợp nhập sai. Tuy nhiên, liên kết có một lỗi trong đó theo tiêu chuẩn nếu số đầu vào quá lớn để phù hợp với loại mục tiêu, hành vi không được xác định.

    #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. Sử dụng các luồng chuỗi (lần này là luồng chuỗi nhập, istringstream). Một lần nữa, istringstream được sử dụng giống nhưcin . Một lần nữa, đừng nhầm lẫn istringstreamvới istrstream. Cái sau không được dùng nữa.

    #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. Sử dụng tăng từ vựng .

    #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
    }       

    Trong trường hợp đầu vào không lexical_casthợp lệ , hãy ném một loại ngoại lệboost::bad_lexical_cast


4
Tài liệu cplusplus cho atoikhông xuất sắc, nó không chính xác. Nó không đề cập đến rằng nếu giá trị số của chuỗi không thể được biểu diễn trong int, thì hành vi là không xác định. Thay vào đó, nó nói rằng các giá trị nằm ngoài phạm vi được kẹp vào INT_MAX/ INT_MIN, mà tôi không thể tìm thấy trong C ++ 03 hoặc C89. Đối với đầu vào không đáng tin cậy / chưa được xác minh hoặc khi xử lý các cơ sở mà luồng không hỗ trợ, bạn cần strtolcó hành vi lỗi đã xác định. Và các nhận xét tương tự cho atof/ strtod.
Steve Jessop

2
cplusplus.com sai về "atoi". Nó cho biết về giá trị trả về "Nếu không có chuyển đổi hợp lệ nào có thể được thực hiện, giá trị bằng không sẽ được trả về. Nếu giá trị chính xác nằm ngoài phạm vi giá trị có thể biểu diễn, INT_MAX hoặc INT_MIN được trả về.", Nhưng thông số cho biết "Nếu giá trị của kết quả không thể được đại diện, hành vi là hoàn tác. " và rằng "Ngoại trừ hành vi bị lỗi, chúng tương đương với (int)strtol(nptr, (char **)NULL, 10). Các hàm atoi [...] trả về giá trị đã chuyển đổi.". cplusplus.com được biết đến là một nguồn thông tin không tốt cho người mới bắt đầu.
Johannes Schaub - litb

istr >> i1 >> f >> i2;bỏ lỡ một séc thành công.
sbi

4
Có thể muốn thêmstd::to_string
Pubby

1
@ArmenTsirunyan: +10 từ cuối của tôi, Một trong những câu trả lời hay nhất mà tôi từng thấy quá sâu. Cảm ơn câu trả lời của bạn.
Abhineet

4

Trong C ++ 17, các hàm mới std :: to_charsstd :: from_chars được giới thiệu trong header charconv .

std :: to_chars không phụ thuộc vào ngôn ngữ, không phân bổ và không ném.

Chỉ một nhóm nhỏ các chính sách định dạng được sử dụng bởi các thư viện khác (chẳng hạn như std :: sprintf) được cung cấp.

Từ std :: to_chars , tương tự cho std :: from_chars .

Đảm bảo rằng std :: from_chars có thể khôi phục mọi giá trị dấu phẩy động được định dạng bởi to_chars chính xác chỉ được cung cấp nếu cả hai hàm đều được triển khai giống nhau

 // 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);
}

Mặc dù nó không được trình biên dịch thực hiện đầy đủ, nhưng nó chắc chắn sẽ được thực hiện.


0

Tôi đã đánh cắp lớp convienent này từ một nơi nào đó tại StackOverflow để chuyển đổi bất kỳ thứ gì có thể truyền trực tuyến thành một chuỗi:

// 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_;
};

Và sau đó bạn sử dụng nó như là;

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

Khá tiện lợi!

Ngoài ra, tôi sử dụng chức năng này để chuyển đổi chuỗi thành bất kỳ thứ gì có thể truyền trực tuyến, thông qua nó không an toàn lắm nếu bạn cố gắng phân tích cú pháp một chuỗi không chứa số; (và nó cũng không thông minh bằng cái cuối cùng)

// 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;
}

Sử dụng như là:

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

Bạn cũng có thể muốn các phiên bản cho wstrings.


5
Đây chính xác là những gì boost :: lexical_cast làm. Và tăng cường thực hiện nó trong một sự phát triển chung chung hơn.
Armen Tsirunyan

Đúng vậy, tôi đã đọc lướt qua câu trả lời đầu tiên và không thấy phần tăng :: lexical_casts.
Viktor Sehr
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.