std :: chuỗi to char *


335

Tôi muốn chuyển đổi chuỗi std :: thành char * hoặc char [] kiểu dữ liệu .

std::string str = "string";
char* chr = str;

Kết quả trong: “lỗi: không thể chuyển đổi 'std :: string' thành 'char' ...” .

Những phương pháp có sẵn để làm điều này?

Câu trả lời:


671

Nó sẽ không tự động chuyển đổi (cảm ơn chúa). Bạn sẽ phải sử dụng phương thức c_str()để có được phiên bản chuỗi C.

std::string str = "string";
const char *cstr = str.c_str();

Lưu ý rằng nó trả về a const char *; bạn không được phép thay đổi chuỗi kiểu C được trả về c_str(). Nếu bạn muốn xử lý nó, bạn sẽ phải sao chép nó trước:

std::string str = "string";
char *cstr = new char[str.length() + 1];
strcpy(cstr, str.c_str());
// do stuff
delete [] cstr;

Hoặc trong C ++ hiện đại:

std::vector<char> cstr(str.c_str(), str.c_str() + str.size() + 1);

4
@Kerrek SB: Đó là một ví dụ, sẽ sử dụng một con trỏ thông minh trong mã thực, hoặc nhiều khả năng tránh c_strhoàn toàn sự điên rồ này .
orlp

14
Câu trả lời là cồng kềnh, không linh hoạt, không cục bộ, sử dụng mảng thô và đòi hỏi sự chú ý đến an toàn ngoại lệ. vectorđã được phát minh chính xác như một trình bao bọc cho các mảng động, do đó, không sử dụng nó có vẻ như là một cơ hội bị bỏ lỡ tốt nhất và vi phạm tinh thần của C ++ ở mức tồi tệ nhất.
Kerrek SB

21
Trước hết, có câu trả lời là cồng kềnh. Đầu tiên tôi giải thích lỗi của OP (nghĩ rằng std::stringsẽ tự động chuyển đổi) và sau đó tôi giải thích anh ta nên sử dụng cái gì, với một mẫu mã ngắn. Suy nghĩ về phía trước tôi cũng giải thích một số tác dụng phụ của việc sử dụng chức năng này, trong đó một tác dụng là bạn không thể chỉnh sửa chuỗi được trả về c_str(). Bạn nhầm tưởng các ví dụ ngắn của tôi là mã giải quyết vấn đề thực sự, nhưng thực tế không phải vậy.
orlp

8
Tôi đánh giá thấp câu trả lời. Câu trả lời này thực sự không hữu ích và thực tế là nó đã được chấp nhận là điều đáng tiếc nhất. Câu trả lời này hoàn toàn bỏ qua các thực tiễn lập trình C ++ tốt và an toàn ngoại lệ và có nhiều giải pháp vượt trội, một số giải pháp được đưa ra trong các câu trả lời khác cho câu hỏi này (ví dụ: câu trả lời được đưa ra bởi ildjarn sử dụng std::vector<char>).
James McNellis

114
@ james-mcnellis, tôi đã chọn câu trả lời này là câu trả lời đúng vì nó đã trả lời CHÍNH XÁC những gì tôi đang yêu cầu ... Không hơn, không kém. Tôi đã không hỏi những gì bạn nghĩ rằng tôi nên làm, tôi đã không yêu cầu một giải pháp khác cho những gì bạn nghĩ rằng tôi đang làm, tôi đã không yêu cầu thực hành tốt. Bạn không biết tôi đang làm việc ở đâu, mã của tôi sẽ được triển khai ở đâu và trong những điều kiện nào. Một số nên học cách đọc, hiểu câu hỏi và trả lời những gì thực sự được hỏi. Không cần phải thể hiện ở đây.

147

Thêm chi tiết ở đây , và ở đây nhưng bạn có thể sử dụng

string str = "some string" ;
char *cstr = &str[0];

15
FWIW, trong cuốn sách của tôi, đây là câu trả lời đúng duy nhất cho câu hỏi thực sự được hỏi. Một chuỗi std :: vốn dĩ có thể thay đổi: những người đang tạo ra âm thanh giống như sửa đổi nội dung của chuỗi là bằng cách nào đó công việc của quỷ dường như thiếu thực tế này.
Jay Freeman -saurik-

2
vâng, đây là câu trả lời đúng thật ngớ ngẩn khi, với tần suất sử dụng, không có một phương pháp nổi bật nào để làm điều này, như bộ khóa của msoft.
Erik Aronesty

1
Tôi đổi 0 thành 0u. Bởi vì một số trình biên dịch / thư viện sẽ (tin hay không) phàn nàn về sự mơ hồ khi các cảnh báo được bật hoàn toàn cho cấu trúc & str [0]
Erik Aronesty

Tôi nghi ngờ khi str bị xóa, char cstr được tạo thành null. Vì vậy, tôi đoán ở đây chỉ có một con trỏ của chuỗi được gán cho con trỏ char. Vì vậy, việc chuyển đổi chuỗi thành char không hoàn toàn theo nghĩa đen. Chuỗi chỉ được trỏ đến char * nhưng giá trị của nó không được chuyển đổi. Tôi có đúng không ???
Samitha Chathuranga

5
Lưu ý rằng đây chỉ là C ++ 11. Các phiên bản trước có thể không có bộ nhớ liên tục hoặc thiếu null kết thúc
Flamefire

40

Nếu tôi cần một bản sao thô có thể thay đổi của nội dung chuỗi của c ++, thì tôi sẽ làm điều này:

std::string str = "string";
char* chr = strdup(str.c_str());

và sau đó:

free(chr); 

Vậy tại sao tôi không nghịch ngợm với std :: vector hoặc [] mới như bất kỳ ai khác? Bởi vì khi tôi cần một chuỗi char * kiểu thô có thể thay đổi, thì vì tôi muốn gọi mã C làm thay đổi chuỗi và mã C xử lý công cụ với free () và cấp phát với malloc () (strdup sử dụng malloc) . Vì vậy, nếu tôi chuyển chuỗi thô của mình cho một số hàm X được viết bằng C,có thể có một ràng buộc đối với đối số của nó là nó phải được phân bổ trên heap (ví dụ nếu hàm có thể muốn gọi realloc trên tham số). Nhưng rất khó có khả năng nó sẽ mong đợi một đối số được phân bổ với (một số người dùng được xác định lại) mới []!


Bạn nên giải thích từ đâu strdupđến.
LF

22

(Câu trả lời này chỉ áp dụng cho C ++ 98.)

Xin vui lòng, không sử dụng một nguyên char*.

std::string str = "string";
std::vector<char> chars(str.c_str(), str.c_str() + str.size() + 1u);
// use &chars[0] as a char*

1
Tôi thực sự chỉ cần một cái gì đó như thế này sớm hơn ngày hôm nay. Tôi đã tự hỏi, liệu có ổn không khi nói vector<char>(str.c_str(), str.c_str() + str.size() + 1), mà không gán con trỏ char tạm thời?
Kerrek SB

1
@Kerrek: Có, giá trị trả về std::basic_string<>::c_str()là hợp lệ cho đến khi stringthay đổi hoặc bị hủy. Điều này cũng ngụ ý rằng nó trả về cùng một giá trị cho các cuộc gọi tiếp theo miễn stringlà không được sửa đổi.
ildjarn

2
@friendzis: Không có tốc độ hoặc không gian trên không sử dụng vectortheo cách này. Và nếu người ta viết mã an toàn ngoại lệ mà không có cơ chế RAII (nghĩa là sử dụng các con trỏ thô), thì độ phức tạp của mã sẽ cao hơn nhiều so với lớp lót đơn giản này.
ildjarn

7
Đó là một huyền thoại vectorcó số lượng lớn chi phí và sự phức tạp. Nếu yêu cầu của bạn là bạn có một mảng char có thể thay đổi , thì trên thực tế, một vectơ ký tự là khá nhiều trình bao bọc C ++ lý tưởng. Nếu yêu cầu của bạn thực sự chỉ cần gọi một con trỏ const-char, thì chỉ cần sử dụng c_str()và bạn đã hoàn thành.
Kerrek SB


15
  • Nếu bạn chỉ muốn một chuỗi kiểu C đại diện cho cùng một nội dung:

    char const* ca = str.c_str();
  • Nếu bạn muốn một chuỗi kiểu C có nội dung mới , một cách (cho rằng bạn không biết kích thước chuỗi tại thời gian biên dịch) là phân bổ động:

    char* ca = new char[str.size()+1];
    std::copy(str.begin(), str.end(), ca);
    ca[str.size()] = '\0';

    Đừng quên delete[]nó sau.

  • Thay vào đó, nếu bạn muốn một mảng được phân bổ tĩnh, có độ dài giới hạn:

    size_t const MAX = 80; // maximum number of chars
    char ca[MAX] = {};
    std::copy(str.begin(), (str.size() >= MAX ? str.begin() + MAX : str.end()), ca);

std::stringkhông hoàn toàn chuyển đổi sang các loại này vì lý do đơn giản là cần phải làm điều này thường là mùi thiết kế. Hãy chắc chắn rằng bạn thực sự cần nó.

Nếu bạn chắc chắn cần một char*, cách tốt nhất có lẽ là:

vector<char> v(str.begin(), str.end());
char* ca = &v[0]; // pointer to start of vector

1
Tại sao &str.front(), &str.back()(không có trong C ++ 03) thay vì phổ biến hơn str.begin()str.end()?
Armen Tsirunyan

1
những gì về str.begin(), hoặc thậm chí std::begin(str), giống như lặp? Tôi không tin stringcó bất kỳ nghĩa vụ phải ở trong bộ nhớ tiếp giáp như thế vector, hoặc có nó?
xtofl

1
@xtofl: Tôi đã chỉnh sửa chúng trong. Và vâng, kể từ C ++ 11 có nghĩa vụ; điều này được ngầm định trong C ++ 03.
Các cuộc đua nhẹ nhàng trong quỹ đạo

@xtofl: Không có trong C ++ 03. Trong C ++ 11, chúng ta có sự đảm bảo đó, cùng với các hàm front () và back (), đã bị sử dụng sai trong câu trả lời ban đầu
Armen Tsirunyan

1
@Tomalak: Họ đã bị lạm dụng ở chỗ bạn cần &back() + 1chứ không phải&back()
Armen Tsirunyan

12

Điều này sẽ tốt hơn khi nhận xét về câu trả lời của bobobobo, nhưng tôi không có đại diện cho điều đó. Nó hoàn thành điều tương tự nhưng với thực tiễn tốt hơn.

Mặc dù các câu trả lời khác là hữu ích, nhưng nếu bạn cần chuyển đổi std::stringthành char*rõ ràng mà không cần const, const_castlà bạn của bạn.

std::string str = "string";
char* chr = const_cast<char*>(str.c_str());

Lưu ý rằng điều này sẽ không cung cấp cho bạn một bản sao của dữ liệu; nó sẽ cung cấp cho bạn một con trỏ tới chuỗi. Do đó, nếu bạn sửa đổi một yếu tố chr, bạn sẽ sửa đổi str.


7

Giả sử bạn chỉ cần một chuỗi kiểu C để vượt qua làm đầu vào:

std::string str = "string";
const char* chr = str.c_str();

5

Để được mô tả nghiêm ngặt, bạn không thể "chuyển đổi chuỗi std :: thành kiểu dữ liệu char * hoặc char []."

Như các câu trả lời khác đã hiển thị, bạn có thể sao chép nội dung của chuỗi std :: sang một mảng char hoặc tạo một const char * vào nội dung của chuỗi std :: để bạn có thể truy cập nó theo kiểu "C" .

Nếu bạn đang cố gắng thay đổi nội dung của chuỗi std ::, kiểu chuỗi std :: có tất cả các phương thức để làm bất cứ điều gì bạn có thể cần làm với nó.

Nếu bạn đang cố gắng chuyển nó đến một số hàm có char *, thì có std :: string :: c_str ().


4

Vì sự trọn vẹn, đừng quên std::string::copy().

std::string str = "string";
const size_t MAX = 80;
char chrs[MAX];

str.copy(chrs, MAX);

std::string::copy()NUL không chấm dứt. Nếu bạn cần đảm bảo bộ kết thúc NUL để sử dụng trong các hàm chuỗi C:

std::string str = "string";
const size_t MAX = 80;
char chrs[MAX];

memset(chrs, '\0', MAX);
str.copy(chrs, MAX-1);

4

Đây là một phiên bản mạnh mẽ hơn từ Protocol Buffer

char* string_as_array(string* str)
{
    return str->empty() ? NULL : &*str->begin();
}

// test codes
std::string mystr("you are here");
char* pstr = string_as_array(&mystr);
cout << pstr << endl; // you are here

+1 để kiểm tra xem chuỗi có trống không. Tôi cũng sẽ thêm một kiểm tra để đảm bảo rằng chuỗi không bị chấm dứt: if (str[str.length()-1] != 0) str.push_back(0)
GaspardP

4

Chuyển đổi theo kiểu OOP

chuyển đổi.hpp

class StringConverter {
    public: static char * strToChar(std::string str);
};

chuyển đổi.cpp

char * StringConverter::strToChar(std::string str)
{
    return (char*)str.c_str();
}

sử dụng

StringConverter::strToChar("converted string")

Tôi thích cách cast để char * loại bỏ const khỏi đầu ra của c_str, tôi nghĩ lý do c_str trả về const char * là để loại bỏ các vấn đề truy cập bộ nhớ tiềm năng, bằng cách cung cấp phiên bản chỉ đọc của điều đó. OP muốn có char *, nhưng tôi nghĩ rằng anh ta có thể được phục vụ tốt hơn bởi đầu ra const char * của c_str, vì điều đó an toàn hơn và các hàm lấy char * cũng thường dùng const char * (giả sử các hàm không làm bất cứ điều gì như thay đổi đầu vào của họ, mà nói chung, họ không nên).
Felipe Valdes


3

Ngoài ra, bạn có thể sử dụng các vectơ để có được một char * có thể ghi * như được trình bày dưới đây;

//this handles memory manipulations and is more convenient
string str;
vector <char> writable (str.begin (), str.end) ;
writable .push_back ('\0'); 
char* cstring = &writable[0] //or &*writable.begin () 

//Goodluck  

Điều này sẽ phân bổ bộ nhớ mới cho vector và sau đó sao chép từng ký tự. std :: chuỗi đã là một thùng chứa, bạn cũng có thể đẩy_back (0) vào chuỗi của mình và thực hiện & str [0]
GaspardP

3

Bạn có thể làm cho nó bằng cách sử dụng iterator.

std::string str = "string";
std::string::iterator p=str.begin();
char* chr = &(*p);

Chúc may mắn.


3

Phiên bản an toàn của câu trả lời char * của orlp bằng unique_ptr:

std::string str = "string";
auto cstr = std::make_unique<char[]>(str.length() + 1);
strcpy(cstr.get(), str.c_str());

3

Để có được một const char *từ std::stringsử dụng c_str()chức năng thành viên:

std::string str = "string";
const char* chr = str.c_str();

Để có được một non-const char *từ một std::stringbạn có thể sử dụng data()hàm thành viên trả về một con trỏ không const từ C ++ 17:

std::string str = "string";
char* chr = str.data();

Đối với các phiên bản cũ hơn của ngôn ngữ, bạn có thể sử dụng cấu trúc phạm vi để sao chép chuỗi vào một vectơ mà từ đó có thể lấy được một con trỏ không phải là con trỏ:

std::string str = "string";
std::vector<char> str_copy(str.c_str(), str.c_str() + str.size() + 1);
char* chr = str_copy.data();

Nhưng hãy cẩn thận rằng điều này sẽ không cho phép bạn sửa đổi chuỗi chứa trong đó str, chỉ có thể thay đổi dữ liệu của bản sao theo cách này. Lưu ý rằng nó đặc biệt quan trọng trong các phiên bản cũ hơn của ngôn ngữ được sử dụng c_str()ở đây vì trước đó std::stringkhông được đảm bảo sẽ bị hủy cho đến khi c_str()được gọi.


2

Điều này cũng sẽ làm việc

std::string s;
std::cout<<"Enter the String";
std::getline(std::cin, s);
char *a=new char[s.size()+1];
a[s.size()]=0;
memcpy(a,s.c_str(),s.size());
std::cout<<a;  
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.