std :: string เป็นถ่าน *


335

ฉันต้องการแปลงstd :: stringเป็นchar *หรือchar []ชนิดข้อมูล

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

ผลการค้นหาใน: “ข้อผิดพลาด: ไม่สามารถแปลง 'มาตรฐาน :: สตริง' เป็น 'ถ่าน' ...”

มีวิธีการอะไรให้ทำเช่นนี้?

c++  string  char 

คำตอบ:


672

มันจะไม่แปลงโดยอัตโนมัติ (ขอบคุณพระเจ้า) คุณจะต้องใช้วิธีc_str()การรับรุ่นสตริง C

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

โปรดทราบว่ามันส่งกลับconst char *; คุณไม่ได้รับอนุญาตให้เปลี่ยนสตริง c_str()C-สไตล์ที่ส่งกลับโดย หากคุณต้องการประมวลผลคุณจะต้องคัดลอกก่อน:

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

หรือใน C ++ ที่ทันสมัย:

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

4
@ Kerrek SB: มันเป็นตัวอย่างที่จะใช้ตัวชี้สมาร์ทในรหัสจริงหรือมีแนวโน้มที่จะหลีกเลี่ยงc_strความบ้าคลั่งนี้อย่างสมบูรณ์
orlp

14
คำตอบนั้นใหญ่โตไม่ซับซ้อนไม่ใช่ในท้องถิ่นใช้อาร์เรย์ดิบและต้องให้ความสนใจกับข้อยกเว้นด้านความปลอดภัย vectorได้รับการคิดค้นอย่างแม่นยำในฐานะเสื้อคลุมสำหรับอาเรย์แบบไดนามิกดังนั้นจึงไม่ได้ใช้มันดูเหมือนเป็นโอกาสที่ไม่ได้รับอย่างดีที่สุดและเป็นการละเมิดจิตวิญญาณของซีพลัสพลัสที่แย่ที่สุด
Kerrek SB

21
ก่อนอื่นใช่คำตอบนั้นใหญ่โต ก่อนอื่นฉันอธิบายข้อผิดพลาดของ OP (คิดว่าstd::stringจะแปลงโดยอัตโนมัติ) จากนั้นฉันอธิบายสิ่งที่เขาควรใช้พร้อมตัวอย่างโค้ดสั้น ๆ c_str()คิดไปข้างหน้าฉันยังอธิบายผลข้างเคียงบางส่วนของการใช้งานของฟังก์ชั่นนี้ที่หนึ่งคือการที่คุณไม่สามารถแก้ไขสตริงส่งกลับโดย คุณเห็นตัวอย่างสั้น ๆ ของฉันผิดว่าเป็นรหัสแก้ปัญหาที่แท้จริงซึ่งไม่ใช่
orlp

8
ฉันลดคำตอบลง คำตอบนี้ไม่มีประโยชน์จริง ๆ และความจริงที่ว่ามันได้รับการยอมรับเป็นโชคร้ายที่สุด คำตอบนี้ไม่สนใจแนวทางการเขียนโปรแกรม C ++ ที่ดีและความปลอดภัยยกเว้นและมีวิธีแก้ปัญหาที่เหนือกว่าซึ่งบางคำตอบในคำถามอื่น (เช่นคำตอบของ ildjarn ที่ใช้std::vector<char>)
James McNellis

114
@ james-mcnellis ฉันเลือกคำตอบนี้เป็นคำตอบที่ถูกต้องเพราะตอบตรงสิ่งที่ฉันขอ ... ไม่มากไม่น้อย ฉันไม่ได้ขอสิ่งที่คุณคิดว่าฉันควรทำฉันไม่ได้ขอคำตอบที่แตกต่างจากสิ่งที่คุณคิดว่าฉันกำลังทำอยู่ฉันไม่ได้ขอแนวทางปฏิบัติที่ดี คุณไม่มีความคิดในสิ่งที่ฉันกำลังทำงานอยู่ซึ่งรหัสของฉันจะถูกนำไปใช้และภายใต้เงื่อนไขใด บางคนควรเรียนรู้ที่จะอ่านเข้าใจคำถามและตอบสิ่งที่ถามจริง ไม่จำเป็นต้องอวดที่นี่

150

รายละเอียดเพิ่มเติมที่นี่และที่นี่แต่คุณสามารถใช้

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

15
FWIW ในหนังสือของฉันนี่เป็นคำตอบที่ถูกต้องสำหรับคำถามที่ถามจริง std :: string สามารถเปลี่ยนแปลงได้โดยกำเนิด: คนที่ทำให้มันฟังดูเหมือนการดัดแปลงเนื้อหาของสายนั้นงานของปีศาจดูเหมือนจะหายไปจากข้อเท็จจริงนี้
Jay Freeman -saurik-

2
ใช่นี่คือคำตอบที่ถูกต้อง เป็นเรื่องโง่ ๆ ที่ได้รับความถี่ในการใช้งานไม่มีวิธีมาตรฐานในการทำเช่นนี้เช่น lockbuffer ของ msoft
Erik Aronesty

1
ฉันเปลี่ยน 0 เป็น 0u เพราะคอมไพเลอร์ /
ไลบรารี่

ฉันสงสัยว่าเมื่อ Str ถูกลบไปแล้วถ่านcstr จะเป็นโมฆะ ดังนั้นฉันเดาว่าที่นี่มีเพียงตัวชี้ของสตริงเท่านั้นที่กำหนดให้กับตัวชี้ถ่าน ดังนั้นการแปลงสตริงเป็นอักขระจึงไม่สมบูรณ์ String จะชี้ไปที่ char * เท่านั้น แต่ค่าจะไม่ถูกแปลง ฉันถูกไหม???
Samitha Chathuranga

5
โปรดทราบว่านี่คือ C ++ 11 เท่านั้น รุ่นก่อนหน้าอาจไม่มีที่เก็บข้อมูลต่อเนื่องหรือขาดโมฆะการสิ้นสุด
Flamefire

39

หากฉันต้องการสำเนาดิบของเนื้อหาสตริงของ c ++ ที่ผันแปรไม่ได้ฉันจะทำดังนี้:

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

และหลังจากนั้น:

free(chr); 

แล้วทำไมฉันถึงไม่เล่นกับ std :: vector หรือ new [] เหมือนใคร? เพราะเมื่อฉันต้องไม่แน่นอนแบบ C ถ่านดิบ * สตริงแล้วเพราะผมต้องการที่จะเรียกรหัส C ซึ่งการเปลี่ยนแปลงสตริงและรหัส C deallocates สิ่งที่มีฟรี () และจัดสรรกับ malloc () (ใช้ strdup malloc) ดังนั้นถ้าฉันส่งสตริงดิบของฉันไปยังฟังก์ชั่น X ที่เขียนใน Cมันอาจมีข้อ จำกัด ในการโต้แย้งว่ามันต้องจัดสรรบนฮีป (ตัวอย่างเช่นถ้าฟังก์ชันอาจต้องการเรียก realloc บนพารามิเตอร์) แต่ไม่น่าเป็นไปได้สูงที่จะคาดว่าจะมีการจัดสรรอาร์กิวเมนต์ด้วย (บางส่วนที่ผู้ใช้กำหนดใหม่) ใหม่ []!


คุณควรอธิบายว่าstrdupมาจากไหน
LF

22

(คำตอบนี้ใช้กับ C ++ 98 เท่านั้น)

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
วันนี้ฉันต้องการอะไรแบบนี้มาก่อน ฉันสงสัยว่ามันโอเคที่จะพูดvector<char>(str.c_str(), str.c_str() + str.size() + 1)หรือไม่โดยไม่ได้กำหนดตัวชี้ถ่านให้เป็นแบบชั่วคราว?
Kerrek SB

1
@Kerrek: ใช่ค่าส่งคืนของstd::basic_string<>::c_str()ถูกต้องจนกว่าstringจะมีการเปลี่ยนแปลงหรือถูกทำลาย นี่ก็หมายความว่ามันจะส่งกลับค่าเดียวกันในการโทรครั้งต่อไปตราบใดที่stringไม่ได้แก้ไข
ildjarn

2
@friendzis: ไม่มีการใช้ความเร็วหรือพื้นที่ว่างvectorในการใช้วิธีนี้ และถ้ามีใครที่จะเขียนโค้ดที่มีข้อยกเว้นที่ปลอดภัยโดยไม่มีกลไก RAII (เช่นการใช้ตัวชี้แบบดิบ) ความซับซ้อนของรหัสจะสูงกว่าการซับแบบง่าย ๆ แบบนี้มาก
ildjarn

7
มันเป็นตำนานที่ vectorมีค่าใช้จ่ายและความซับซ้อนจำนวนมาก หากความต้องการของคุณคือคุณมีอาร์เรย์ char ที่ไม่แน่นอนในความเป็นจริงแล้วเวกเตอร์ของตัวอักษรนั้นเป็นตัวห่อหุ้ม C ++ ในอุดมคติ หากความต้องการของคุณเพียงแค่เรียกตัวชี้ const-char จากนั้นก็ใช้c_str()และคุณทำเสร็จแล้ว
Kerrek SB

3
@ildjarn: ที่จริงแล้ว มันเป็นพื้นเป็น
Lightness Races ที่ Orbit

14
  • หากคุณต้องการสตริง C-style ที่แสดงเนื้อหาเดียวกัน:

    char const* ca = str.c_str();
  • หากคุณต้องการสตริง C-style ที่มีเนื้อหาใหม่วิธีหนึ่ง (เนื่องจากคุณไม่ทราบขนาดสตริงในเวลาคอมไพล์) คือการจัดสรรแบบไดนามิก:

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

    อย่าลืมdelete[]ทีหลัง

  • หากคุณต้องการอาร์เรย์ที่มีความยาวแบบ จำกัด แบบคงที่แทน:

    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::stringไม่ได้แปลงเป็นประเภทเหล่านี้โดยปริยายด้วยเหตุผลง่ายๆที่จำเป็นต้องทำเช่นนี้โดยปกติแล้วจะเป็นกลิ่นของการออกแบบ ตรวจสอบให้แน่ใจว่าคุณต้องการมันจริงๆ

หากคุณแน่นอนต้องมีchar*ที่ดีที่สุดวิธีที่น่าจะเป็น:

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

1
ทำไม&str.front(), &str.back()(ซึ่งไม่มีอยู่ใน C ++ 03) แทนที่จะเป็นเรื่องธรรมดามากกว่าstr.begin()และstr.end()?
Armen Tsirunyan

1
สิ่งที่เกี่ยวกับstr.begin()หรือแม้กระทั่งstd::begin(str), iterator เหมือน? ฉันไม่เชื่อว่าstringมีข้อผูกพันใด ๆ ที่จะต้องอยู่ในความทรงจำที่ต่อเนื่องกันเช่นvectorนี้หรือไม่?
xtofl

1
@xtofl: ฉันแก้ไขไปแล้วและใช่ตั้งแต่ C ++ 11 มีข้อผูกมัด นี่เป็นนัยใน C ++ 03
Lightness Races ในวงโคจร

@xtofl: ไม่อยู่ใน C ++ 03 ใน C ++ 11 เรามีการรับประกันนั้นพร้อมกับฟังก์ชั่นด้านหน้า () และ back () ซึ่งใช้ผิดในคำตอบดั้งเดิมต่อไป
Armen Tsirunyan

1
@ Tomalak: พวกเขาถูกนำไปใช้ในสิ่งที่คุณต้องการ&back() + 1ไม่ใช่&back()
Armen Tsirunyan

12

นี่จะดีกว่าเป็นความคิดเห็นในคำตอบของ bobobobo แต่ฉันไม่มีตัวแทนสำหรับสิ่งนั้น มันประสบความสำเร็จในสิ่งเดียวกัน แต่มีแนวทางปฏิบัติที่ดีกว่า

แม้ว่าคำตอบอื่น ๆ นั้นมีประโยชน์หากคุณจำเป็นต้องแปลงstd::stringเป็นchar*อย่างชัดเจนโดยไม่มี const แต่const_castเป็นเพื่อนของคุณ

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

โปรดทราบว่าสิ่งนี้จะไม่ให้สำเนาของข้อมูลแก่คุณ มันจะให้ตัวชี้ไปยังสตริง ดังนั้นหากคุณปรับเปลี่ยนองค์ประกอบของคุณจะปรับเปลี่ยนchrstr


6

สมมติว่าคุณต้องการสตริง C-style เพื่อส่งผ่านเป็นอินพุต:

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

4

หากต้องการพูดจาหยาบคายอย่างเคร่งครัดคุณไม่สามารถ "แปลง std :: string เป็น char * หรือ char [] ชนิดข้อมูล"

ดังที่คำตอบอื่น ๆ ได้แสดงขึ้นคุณสามารถคัดลอกเนื้อหาของสตริง std :: ไปยังอาร์เรย์ char หรือสร้าง const char * ไปยังเนื้อหาของสตริง std :: เพื่อให้คุณสามารถเข้าถึงได้ใน "C style" .

หากคุณกำลังพยายามเปลี่ยนเนื้อหาของสตริง std :: std :: string type มีวิธีการทั้งหมดที่จะทำทุกอย่างที่คุณอาจจำเป็นต้องทำ

หากคุณพยายามส่งผ่านไปยังฟังก์ชั่นบางตัวที่ใช้ถ่าน * มี std :: string :: c_str ()


4

นี่คืออีกหนึ่งเวอร์ชันที่แข็งแกร่งกว่าจาก 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 สำหรับการตรวจสอบว่าสตริงว่างเปล่า ฉันจะเพิ่มการตรวจสอบเพื่อให้แน่ใจว่าสายเป็นศูนย์สิ้นสุด: if (str[str.length()-1] != 0) str.push_back(0)
GaspardP

4

การแปลงในรูปแบบ OOP

converter.hpp

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

converter.cpp

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

การใช้

StringConverter::strToChar("converted string")

ฉันชอบวิธีการส่งถ่าน * กำจัด const จากเอาต์พุตของ c_str ฉันคิดว่าเหตุผลที่ c_str ส่งคืน const char * คือการกำจัดปัญหาการเข้าถึงหน่วยความจำที่อาจเกิดขึ้นได้โดยการให้สิ่งที่อ่านได้อย่างเดียวเท่านั้น OP ต้องการมี char * แต่ฉันคิดว่าเขาอาจจะได้รับหน้าที่ที่ดีขึ้นโดย const char * ผลลัพธ์ของ c_str แทนเนื่องจากมันปลอดภัยกว่าและฟังก์ชั่นที่ใช้ char * มักจะใช้ char char * เช่นกัน ทำอะไรเช่นเปลี่ยนอินพุตของพวกเขาซึ่งโดยทั่วไปแล้วพวกเขาไม่ควร)
Felipe Valdes

3

std::string::copy()เพื่อประโยชน์ครบถ้วนไม่ลืม

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

str.copy(chrs, MAX);

std::string::copy()NUL ไม่สิ้นสุด หากคุณต้องการตรวจสอบให้แน่ใจว่า NUL terminator สำหรับใช้ในฟังก์ชันสตริง C:

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

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

3

คุณสามารถทำได้โดยใช้ตัววนซ้ำ

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

โชคดี.


3

char * รุ่นที่ปลอดภัยของคำตอบ orlp โดยใช้ unique_ptr:

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

3

วิธีขอรับ a const char *จากการstd::stringใช้c_str()ฟังก์ชันสมาชิก:

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

เพื่อรับ non-const char *จากstd::stringคุณสามารถใช้data()ฟังก์ชั่นสมาชิกซึ่งส่งกลับตัวชี้ที่ไม่ใช่ const ตั้งแต่ C ++ 17:

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

สำหรับภาษาที่เก่ากว่าคุณสามารถใช้การสร้างช่วงเพื่อคัดลอกสตริงลงในเวกเตอร์ซึ่งสามารถรับตัวชี้ที่ไม่ใช่ const ได้:

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

แต่ระวังว่าสิ่งนี้จะไม่อนุญาตให้คุณแก้ไขสตริงที่มีอยู่strเฉพาะข้อมูลของสำเนาเท่านั้นที่สามารถเปลี่ยนแปลงได้ด้วยวิธีนี้ โปรดทราบว่ามันมีความสำคัญเป็นพิเศษในภาษาเวอร์ชันเก่าที่จะใช้c_str()ที่นี่เพราะstd::stringไม่รับประกันว่าจะถูกยกเลิกจนกว่าจะc_str()มีการเรียกใช้



2

หรือคุณสามารถใช้เวคเตอร์เพื่อรับถ่านแบบเขียนได้ * ดังที่แสดงด้านล่าง

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

นี่จะจัดสรรหน่วยความจำใหม่สำหรับเวกเตอร์แล้วคัดลอกอักขระแต่ละตัว std :: string เป็นคอนเทนเนอร์อยู่แล้วคุณอาจจะ push_back (0) เข้ากับสตริงของคุณและ & str [0]
GaspardP

1

สิ่งนี้จะได้ผล

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;  
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.