Kaip konvertuoti std :: string į const char * arba char *?

Kaip konvertuoti std::string į char* arba const char* ?

780
07 дек. nustatė user37875 07 dec. 2008-12-07 22:30 '08, 10.30 val. 2008-12-07 22:30
@ 8 atsakymai

Jei norite tiesiog perduoti std::string funkciją į const char* , galite naudoti

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

Jei norite gauti įrašomą kopiją, pvz., char * , galite tai padaryti šiuo būdu:

 std::string str; char * writable = new char[str.size() + 1]; std::copy(str.begin(), str.end(), writable); writable[str.size()] = '\0'; // don't forget the terminating 0 // don't forget to free the string after finished using it delete[] writable; 

Keisti . Atkreipkite dėmesį, kad minėtos nuostatos nėra saugios išimtims. Jei kažkas tarp skambučio iš new ir skambinimo delete sukelia atminties nutekėjimą, nes niekas automatiškai neskambins. Yra du būdai išspręsti šią problemą.

padidinti :: scoped_array

boost::scoped_array pašalins atmintį, kai išeisite iš taikymo srities:

 std::string str; boost::scoped_array<char> writable(new char[str.size() + 1]); std::copy(str.begin(), str.end(), writable.get()); writable[str.size()] = '\0'; // don't forget the terminating 0 // get the char* using writable.get() // memory is automatically freed if the smart pointer goes // out of scope 

std :: vektorius

Tai yra standartinis būdas (nereikia išorinės bibliotekos). Jūs naudojate std::vector , kuris visiškai kontroliuoja jūsų atmintį.

 std::string str; std::vector<char> writable(str.begin(), str.end()); writable.push_back('\0'); // get the char* using  or > 
939
07 дек. Atsakymas pateikiamas Johannes Schaub - litb 07 d. 2008-12-07 22:35 '08, 10:35 pm 2008-12-07 22:35

Atsižvelgiant į tai, kad ...

 std::string x = "hello"; 

Gauti „char *“ arba „const char *“ iš „string“

Kaip gauti žymeklį į simbolį, kuris galioja tol, kol x išlieka apimtis ir nekeičia tolesnio

C ++ 11 supaprastina darbą; Toliau pateikiamos prieigos prie to paties vidinio eilutės buferio:

 const char* p_c_str = x.c_str(); const char* p_data = x.data(); const char* p_x0 =  char* p_x0_rw =  // compiles iff x is not const... 

Visuose aukščiau nurodytuose taškuose bus ta pati vertė - pirmosios žymos adresas buferyje. Net tuščioje eilutėje yra „pirmasis simbolis buferyje“, nes C ++ 11 visada įrašo papildomą terminatoriaus simbolį NUL / 0 po aiškiai priskirto eilutės turinio (pvz., std::string("this\0that", 9) turės buferį "this\0that\0" ).

Bet kuriam iš aukščiau nurodytų rodiklių:

 char c = p[n]; // valid for n <= x.size() // ie you can safely read the NUL at p[x.size()] 

Tik rodyklė, ne const Nuo > :

 p_x0_rw[n] = c; // valid for n <= x.size() - 1 // ie don't overwrite the implementation maintained NUL 

NUL rašymas kitoje eilutėje nekeičia string size() ; string leidžiama turėti bet kokį skaičių NULs - ji nenurodo specialaus skambučio std::string (tas pats C ++ 03).

C ++ 03 viskas buvo daug sudėtingesnė (pagrindiniai skirtumai pažymėti ):

  • x.data()

    • grąžina const char* į vidinį eilutės buferį , kurio standartas neprivalo nutraukti su NUL (t.y. jis gali būti ['h', 'e', 'l', 'l', 'o'] , po kurio seka neapibrėžtos arba šiukšlių vertės, su atsitiktine prieiga prie jų su neapibrėžtu elgesiu.
      • x.size() simboliai yra saugūs skaityti, t.y. x[0] per x[x.size() - 1]
      • tuščioms eilutėms garantuojate kitą rodyklę, išskyrus „NULL“, kuriam galite saugiai pridėti 0 („hurray!“), bet neturėtumėte žaisti šio rodyklės.
  • >

    • tuščioms eilutėms šis elgesys yra neapibrėžtas (21.3.4)
      • Pavyzdžiui. nurodomas f(const char* p, size_t n) { if (n == 0) return; ...whatever... } f(const char* p, size_t n) { if (n == 0) return; ...whatever... } neturėtumėte skambinti f( x.size()); kai x.empty() - tiesiog naudokite f(x.data(), ...) .
    • kitaip, pagal x.data() , bet:
      • ne x tai duoda žymeklį ne const char* ; galite perrašyti eilutės turinį
  • x.c_str()

    • grąžina const char* reikšmę reikšmei ASCIIZ (NUL nutrauktas) (t.y. ['h', 'e', ​​'l', 'l', 'o', '0')).
    • Nors neužtenka, jei nuspręsta tai padaryti, C ++ 03 standartas buvo suformuluotas taip, kad eilutės įgyvendinimas galėtų išlaisvinti puikų NUL užbaigtą buferį iš potencialiai ne NUL buferio, veikiančio x.data() ir >
    • x.size() + 1 simbolis yra saugus skaityti.
    • garantuotas saugus net tuščias eilutes (['0']).

Prieigos prie išorinių teisinių rodiklių poveikis

Nepriklausomai nuo to, kaip nurodote žymeklį, neturėtumėte prieiti prie atminties toliau nuo žymeklio nei pirmiau aprašytuose simboliuose. Bandymai tai padaryti turi neapibrėžtą elgesį, turintį tikrą galimybę, kad netgi skaitymo metu susidarys avarijos ir šiukšlių rezultatai, taip pat didelės apimties duomenys, sukrauti pažeidimai ir (arba) saugumo pažeidžiamumai.

Kada šie rodikliai tampa netinkami?

Jei skambinate tam tikra nario funkcijų string , pakeičiančia string ar rezervų papildomą talpą, bet kokie rodyklės dydžiai, kurie buvo iš anksto grąžinti bet kuriuo iš pirmiau minėtų metodų, yra neteisingi. Šiuos metodus galite naudoti dar kartą, kad gautumėte kitą rodiklį. (Taisyklės yra tokios pačios kaip iteratoriams, string s).

Taip pat žr. Kaip gauti žymeklį į simbolį, net ir po to, kai x palieka apimtį ar pakeitimus toliau.

Taigi, kas geriau naudoti?

Iš C ++ 11 naudokite .c_str() duomenis ir .data() „dvejetainiams“ duomenims (paaiškinkite toliau).

Naudodami C ++ 03, naudokite .c_str() jei nėra nustatyta, kad .data() yra tinkamas ir pageidauja .data() virš > , nes jis yra saugus tuščioms eilėms.

... pabandykite suprasti programą, kad galėtumėte naudoti data() jei reikia, arba tikriausiai padarysite kitas klaidas ...

ASCII NUL „0“ .c_str() garantuojamą .c_str() , daugelis funkcijų naudoja kaip kontrolinę vertę, rodančią atitinkamų ir saugių duomenų pabaigą. Tai taikoma tiek „C ++“, tiek funkcijoms, pvz., fstream::fstream(const char* filename, ...) , taip pat ir bendrai naudojamoms su C funkcijoms, pvz., strchr() ir printf() .

Atsižvelgiant į tai, kad C ++ 03 .c_str() užtikrina, kad grąžinamas buferis yra super rinkinys .data() , visada galite saugiai naudoti .c_str() , bet žmonės kartais ne todėl, kad:

  • naudojant .data() bendrauja su kitais programuotojais, kurie skaito šaltinio kodą, kad duomenys nėra ASCIIZ (dažniau naudojate eilutę duomenų blokui (kuris kartais nėra netgi tekstas) saugoti), arba kad perduodate ją kitai funkcijai, kuri traktuoja jį kaip „dvejetainių“ duomenų bloką. Tai gali būti svarbi idėja užtikrinant, kad kitų programuotojų kodų pakeitimai ir toliau teisingai apdorotų duomenis.
  • Tik C ++ 03: yra nedidelė tikimybė, kad jūsų string įgyvendinimas turės atlikti papildomus atminties paskirstymo ir / arba kopijavimo duomenis, kad būtų parengtas nulinis užbaigtas buferis.

Kaip dar vienas užuominas, jei funkcijų parametrai reikalauja ( const ) char* , bet nereikalauja gauti x.size() , funkcija tikriausiai turi būti ASCIIZ, todėl .c_str() yra geras pasirinkimas (funkcija turėtų žinoti, kur tekstas kažkaip baigiasi, todėl jei jis nėra atskiras parametras, jis gali būti tik sąlyginis, pvz., ilgio prefiksas arba kontrolinis signalas arba tam tikras fiksuotas numatomas ilgis.

Kaip gauti žymeklį į simbolį, net ir po to, kai x palieka taikymo sritį ar toliau keičiasi

Straipsnio x turinį reikia nukopijuoti į naują atminties sritį už x . Šis išorinis buferis gali būti daugelyje vietų, pvz., Kitas string arba simbolių masyvo kintamasis, jis gali arba negali turėti kitokio gyvenimo trukmės nei x dėl to, kad jis yra kitoje srityje (pavyzdžiui, vardų erdvė, pasaulinė, statinė , krūva, bendroji atmintis, atminties kartografavimo failas).

Jei norite kopijuoti tekstą iš std::string x į nepriklausomą simbolių grupę:

 // USING ANOTHER STRING - AUTO MEMORY MANAGEMENT, EXCEPTION SAFE std::string old_x = x; // - old_x will not be affected by subsequent modifications to x... // - you can use ` to get a writable char* to old_x textual content // - you can use resize() to reduce/expand the string // - resizing isn't possible from within a function passed only the char* address std::string old_x = x.c_str(); // old_x will terminate early if x embeds NUL // Copies ASCIIZ data but could be less efficient as it needs to scan memory to // find the NUL terminator indicating string length before allocating that amount // of memory to copy into, or more efficient if it ends up allocating/copying a // lot less content. // Example, x == "ab\0cd" -> old_x == "ab". // USING A VECTOR OF CHAR - AUTO, EXCEPTION SAFE, HINTS AT BINARY CONTENT, GUARANTEED CONTIGUOUS EVEN IN C++03 std::vector<char> old_x(x.data(), x.data() + x.size()); // without the NUL std::vector<char> old_x(x.c_str(), x.c_str() + x.size() + 1); // with the NUL // USING STACK WHERE MAXIMUM SIZE OF x IS KNOWN TO BE COMPILE-TIME CONSTANT "N" // (a bit dangerous, as "known" things are sometimes wrong and often become wrong) char y[N + 1]; strcpy(y, x.c_str()); // USING STACK WHERE UNEXPECTEDLY LONG x IS TRUNCATED (eg Hello\0->Hel\0) char y[N + 1]; strncpy(y, x.c_str(), N); // copy at most N, zero-padding if shorter y[N] = '\0'; // ensure NUL terminated // USING THE STACK TO HANDLE x OF UNKNOWN (BUT SANE) LENGTH char* y = alloca(x.size() + 1); strcpy(y, x.c_str()); // USING THE STACK TO HANDLE x OF UNKNOWN LENGTH (NON-STANDARD GCC EXTENSION) char y[x.size() + 1]; strcpy(y, x.c_str()); // USING new/delete HEAP MEMORY, MANUAL DEALLOC, NO INHERENT EXCEPTION SAFETY char* y = new char[x.size() + 1]; strcpy(y, x.c_str()); // or as a one-liner: char* y = strcpy(new char[x.size() + 1], x.c_str()); // use y... delete[] y; // make sure no break, return, throw or branching bypasses this // USING new/delete HEAP MEMORY, SMART POINTER DEALLOCATION, EXCEPTION SAFE // see boost shared_array usage in Johannes Schaub answer // USING malloc/free HEAP MEMORY, MANUAL DEALLOC, NO INHERENT EXCEPTION SAFETY char* y = strdup(x.c_str()); // use y... free(y); 

Kitos priežastys, reikalaujančios char* arba const char* generuojamos iš string

Taigi, pirmiau, pamatėte, kaip gauti ( const ) char* , ir kaip padaryti teksto kopiją nepriklausomai nuo originalo string , bet ką jūs galite su juo daryti? Atsitiktinis pavyzdžių tepimas ...

  • pateikti C + kodo teksto prieigos kodą „C“, kaip ir printf("x is '%s'", x.c_str());
  • nukopijuokite x tekstą į skambinančiojo nurodytą buferį (pvz., strncpy(callers_buffer, callers_buffer_size, x.c_str()) arba nepastovią atmintį, naudojamą įrenginio I / O (pvz., for (const char* p = x.c_str(); *p; ++p) *p_device = *p; )
  • pridėti tekstą x prie simbolių masyvo, kuriame jau yra tam tikras ASCIIZ tekstas (pvz., strcat(other_buffer, x.c_str()) ) - būkite atsargūs strcat(other_buffer, x.c_str()) buferio (daugeliu atvejų jums gali tekti naudoti strncat )
  • grąžinti const char* arba char* iš funkcijos (galbūt dėl ​​istorinių priežasčių - klientas, kuris naudoja jūsų esamą API) arba suderinamumą su C, nenorite grąžinti std::string , bet norite kopijuoti savo string duomenis skambinančiajam)
    • būkite atsargūs, kad negrąžintumėte žymeklio, kurį skambintojas gali nukreipti po vietinės kintamosios string , kurią žymeklis nurodė paliekant sritį
    • Kai kurie projektai su bendrais objektais, sukompiliuoti / susieti su skirtingomis std::string (pvz., STLport ir gimtojo kompiliatoriaus) realizacijomis, gali perduoti duomenis kaip ASCIIZ, kad išvengtų konfliktų.
173
11 нояб. Atsakymą pateikė Tony Delroy 11 nov. 2010-11-11 12:21 '10, 12:21, 2010-11-11 12:21

Naudokite .c_str() metodą const char * .

Galite naudoti > kad gautumėte char * rodyklę, tačiau yra pora gotcha: jūs nebūtinai gausite nulinę eilutę ir negalite pakeisti eilutės dydžio. Jums ypač reikia būti atsargiems, kad į eilutės pabaigą nebūtų pridėti simbolių, kitaip gausite buferio perpildymą (ir galimą gedimą).

Nebuvo jokių garantijų, kad visi simboliai būtų to paties nepertraukiamo buferio dalis iki C ++ 11, bet praktiškai visi žinomi std::string buvo bet kokie; žr. Ar „ s [0]“ nurodo nuolatinius simbolius std :: string? .

Atkreipkite dėmesį, kad daugelis string narių funkcijų perskirstys vidinį buferį ir panaikins bet kokius taškus, kuriuos galite išsaugoti. Geriausia juos nedelsiant naudoti ir atsisakyti.

31
07 дек. Atsakymas, kurį pateikė Mark Ransom 07 Dec 2008-12-07 22:31 '08, 10:31 pm 2008-12-07 22:31

C ++ 17

C ++ 17 (toliau pateikiamas standartas) keičia trumpą basic_string šablono aprašymą, pridėdamas ne nuolatinį data() perkrovą:

charT* data() noexcept;

Grąžina: rodyklę p, kad p + i == ir operatorius kiekvienam i iš [0, dydis ()]. Eik


CharT const *std::basic_string<CharT>

 std::string const cstr = { "..." }; char const * p = cstr.data(); // or .c_str() 

CharT *std::basic_string<CharT>

 std::string str = { "..." }; char * p = str.data(); 

C ++ 11

CharT const *std::basic_string<CharT>

 std::string str = { "..." }; str.c_str(); 

CharT *std::basic_string<CharT>

Nuo C ++ 11 standartas sako:

  • Pagrindiniai elementai pagrindiniame basic_string turi būti saugomi tarpusavyje. Tai reiškia, kad bet kuriam basic_string s objektui identifikatorius + n) == + n bus vykdomi visoms n reikšmėms, kad 0 <= n < s.size() .

  1. const_reference operator[](size_type pos) const;
    reference operator[](size_type pos);

    Grąžina: *(begin() + pos) jei pos < size() , kitaip nuoroda į CharT tipo CharT , kurio vertė yra CharT() ; pamatinė vertė neturėtų būti keičiama.


    1. const charT* c_str() const noexcept;
      const charT* data() const noexcept;

      Grąžina: rodyklę p, kad p + i == > kiekvienam i [0,size()] .

Yra įmanomų būdų, kaip gauti rodyklę į ne kontinentinį simbolį.

1. Naudoti nuolatinį saugojimą C ++ 11

 std::string foo{"text"}; auto p = > 

Pro

  • Paprastas ir trumpas
  • Greitas (tik metodas be kopijavimo)

prieš

  • Galutinė '\0' neturėtų būti keičiama / nebūtinai turi būti ne nuolatinės atminties dalis.

2. Naudokite std::vector<CharT>

 std::string foo{"text"}; std::vector<char> fcv(foo.data(), foo.data()+foo.size()+1u); auto p = fcv.data(); 

Pro

  • Paprasta
  • Automatinis atminties apdorojimas
  • Dinaminis

prieš

  • Reikalinga eilutės kopija

3. Naudokite std::array<CharT, N> jei n yra kompiliavimo laiko konstanta (ir pakankamai maža)

 std::string foo{"text"}; std::array<char, 5u> fca; std::copy(foo.data(), foo.data()+foo.size()+1u, fca.begin()); 

Pro

  • Paprasta
  • Versti atminties valdymą

prieš

  • Statinis
  • Reikalinga eilutės kopija

4. Žalios atminties pasiskirstymas su automatiniu saugyklos pašalinimu

 std::string foo{ "text" }; auto p = std::make_unique<char[]>(foo.size()+1u); std::copy(foo.data(), foo.data() + foo.size() + 1u, > 

Pro

  • Mažas pėdsakas
  • Automatinis trynimas
  • Paprasta

prieš

  • Reikalinga eilutės kopija
  • Statinis (dinaminis naudojimas reikalauja daug daugiau kodo)
  • Mažiau funkcijų nei vektorius ar masyvas

5. Žalios atminties pasiskirstymas rankiniu būdu

 std::string foo{ "text" }; char * p = nullptr; try { p = new char[foo.size() + 1u]; std::copy(foo.data(), foo.data() + foo.size() + 1u, p); // handle stuff with p delete[] p; } catch (...) { if (p) { delete[] p; } throw; } 

Pro

  • Maksimalus „valdymas“

Con

  • Reikalinga eilutės kopija
  • Didžiausia atsakomybė / jautrumas klaidoms
  • Kompleksas
18
12 янв. Atsakymas yra Pixelchemist Jan 12 2016-01-12 18:53 '16 at 18:53 2016-01-12 18:53

Dirbu su API, turinčiomis daug funkcijų, gaunant char* kaip įvestį.

Šiai problemai spręsti sukūriau nedidelę klasę, pritaikiau RAII idiomas.

 class DeepString { DeepString(const DeepString other); DeepString operator=(const DeepString other); char* internal_; public: explicit DeepString( const string toCopy): internal_(new char[toCopy.size()+1]) { strcpy(internal_,toCopy.c_str()); } ~DeepString() { delete[] internal_; } char* str() const { return internal_; } const char* c_str() const { return internal_; } }; 

Ir galite jį naudoti kaip:

 void aFunctionAPI(char* input); // other stuff aFunctionAPI("Foo"); //this call is not safe. if the function modified the //literal string the program will crash std::string myFoo("Foo"); aFunctionAPI(myFoo.c_str()); //this is not compiling aFunctionAPI(const_cast<char*>(myFoo.c_str())); //this is not safe std::string //implement reference counting and //it may change the value of other //strings as well. DeepString myDeepFoo(myFoo); aFunctionAPI(myFoo.str()); //this is fine 

Aš pavadinau klasę „ DeepString nes ji sukuria gilų ir unikalų egzistuojančios eilutės kopiją ( DeepString nėra nukopijuota).

9
29 марта '11 в 16:32 2011-03-29 16:32 atsakymą pateikė „ Alessandro Teruzzi “ kovo 29 d. 11 val. 16:32 2011-03-29 16:32

Tiesiog perskaitykite tai:

 string str1("stackoverflow"); const char * str2 = str1.c_str(); 

Tačiau atkreipkite dėmesį, kad tai grąžins const char * . Jei naudojate char * naudokite strcpy kad nukopijuotumėte jį į kitą char masyvą.

7
12 мая '13 в 11:18 2013-05-12 11:18 atsakymas duotas pjūklui gegužės 13 d., 13 val. 11:18 2013-05-12 11:18
 char* result = strcpy((char*)malloc(str.length()+1), str.c_str()); 
7
12 июля '14 в 15:06 2014-07-12 15:06 atsakymas pateikiamas cegprakash liepos 12 d., 14 val. 15:06 2014-07-12 15:06

Išbandykite

 std::string s(reinterpret_cast<const char *>(Data), Size); 
-4
17 февр. atsakymą pateikė anish 17 vasaris. 2017-02-17 19:45 '17, 7:45 pm 2017-02-17 19:45

Kiti klausimai apie žymes arba Užduoti klausimą