kzen.dev
  • Otázky
  • Značky
  • Používatelia
Oznámenia
Odmeny
Registrácia
Po registrácii budete informovaní o odpovediach a komentároch na vaše otázky.
Prihlásiť sa
Ak už máte konto, prihláste sa a skontrolujte nové oznámenia.
Za pridané otázky, odpovede a komentáre budú udelené odmeny.
Viac na
Zdroj
Upraviť
 user37875
user37875
Question

Ako previesť std::string na const char* alebo char*?

Ako môžem konvertovať std::string na char* alebo const char*?

861 2008-12-07T19:30:56+00:00 3
 Niall
Niall
Edited question 6 október 2014 в 7:43
Programovanie
c++
string
const
char
This question has 1 odpoveď in English, to read them log in to your account.
Solution / Answer
Johannes  Schaub - litb
Johannes Schaub - litb
7 december 2008 в 7:35
2008-12-07T19:35:43+00:00
Viac na
Zdroj
Upraviť
#8677295

Ak chcete len odovzdať std::string funkcii, ktorá potrebuje const char*, môžete použiť

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

Ak chcete získať zapisovateľnú kópiu, ako je char *, môžete to urobiť pomocou tohto:

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;

Edit: Všimnite si, že vyššie uvedený postup nie je bezpečný pre výnimky. Ak čokoľvek medzi volaním new a volaním delete vyhodí, dôjde k úniku pamäte, pretože nič za vás automaticky nezavolá delete. Existujú dva okamžité spôsoby, ako to vyriešiť.

boost::scoped_array

boost::scoped_array vám pri výstupe z rozsahu vymaže pamäť:

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::vector

Toto je štandardný spôsob (nevyžaduje žiadnu externú knižnicu). Používate std::vector, ktorý kompletne spravuje pamäť za vás.

std::string str;
std::vector<char> writable(str.begin(), str.end());
writable.push_back('\0');

// get the char* using &writable[0] or &*writable.begin()
 Niall
Niall
Edited answer 6 október 2014 в 7:44
1018
0
Artificial intelligence to parse product page
productapi.dev
Tony Delroy
Tony Delroy
11 november 2010 в 9:21
2010-11-11T09:21:35+00:00
Viac na
Zdroj
Upraviť
#8677297

Vzhľadom na to, že...

std::string x = "hello";

Získanie `char *` alebo `const char*` z `stringu`

**Ako získať ukazovateľ na znak, ktorý'je platný, kým `x` zostáva v obore a nie je'ďalej modifikovaný** **C++11** veci zjednodušuje; všetky nasledujúce spôsoby umožňujú prístup k tej istej vnútornej vyrovnávacej pamäti reťazca:
const char* p_c_str = x.c_str();
const char* p_data  = x.data();
char* p_writable_data = x.data(); // for non-const x from C++17 
const char* p_x0    = &x[0];

      char* p_x0_rw = &x[0];  // compiles iff x is not const...

Všetky uvedené ukazovatele budú mať tú istú hodnotu - adresu prvého znaku v bufferi. Dokonca aj prázdny reťazec má "prvý znak vo vyrovnávacej pamäti", pretože C++11 zaručuje, že za explicitne priradeným obsahom reťazca vždy ponechá dodatočný ukončovací znak NUL/0 (napr. std::string("this\0that", 9) bude mať vyrovnávaciu pamäť s adresou "this\0that\0"). Vzhľadom na ktorýkoľvek z vyššie uvedených ukazovateľov:

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

Len pre nekonštantný ukazovateľ p_writable_data a z &x[0]:

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

Zápis NUL na iné miesto v reťazci nezmení reťazec's size(); reťazec's môže obsahovať ľubovoľný počet NUL - `std::string`` s nimi nezaobchádza nijako špeciálne (rovnako v C++03). V C++03 bolo všetko podstatne komplikovanejšie (kľúčové rozdiely sú zvýraznené***):

  • x.data()
    • vracia const char* do interného buffera reťazca, ktorý podľa normy nemusel byť ukončený NUL (t. j. mohol byť ['h', 'e', 'l', 'l', 'o'] nasledovaný neinicializovanými alebo odpadovými hodnotami, pričom náhodné prístupy k nim mali nedefinované správanie).
      • Znaky x.size() sú bezpečné na čítanie, t. j. x[0] až x[x.size() - 1]
      • pre prázdne reťazce máte zaručený nejaký non-NULL ukazovateľ, ku ktorému môžete bezpečne pridať 0 (hurá!), ale nemali by ste tento ukazovateľ dereferencovať.
  • &x[0]
    • pre prázdne reťazce to má nedefinované správanie (21.3.4)
      • Napr. dané f(const char* p, size_t n) { if (n == 0) return; ...whatever... } nesmiete volať f(&x[0], x.size()); keď x.empty() - stačí použiť f(x.data(), ...).
    • v opačnom prípade ako pri x.data(), ale:
      • pre ne-konštantné x to dáva ne-konštantný znak* ukazovateľ; môžete prepísať obsah reťazca
  • x.c_str()
    • vráti const char* na ASCIIZ (NUL-koncovku) reprezentáciu hodnoty (t.j. ['h', 'e', 'l', 'l', 'o', '\0']).
    • hoci sa pre to rozhodlo len málo implementácií, ak vôbec nejaké, norma C++03 bola formulovaná tak, aby umožnila implementácii reťazca slobodne vytvoriť odlišný buffer ukončený NUL za chodu z potenciálne neukončeného buffera "vystaveného" pomocou x.data() a &x[0]
    • x.size() + 1 znakov je bezpečné čítať.
    • zaručené bezpečné aj pre prázdne reťazce (['\0']). Dôsledky prístupu mimo legálnych indexov

      Nech už získate ukazovateľ akýmkoľvek spôsobom, nesmiete pristupovať do pamäte ďalej od ukazovateľa, ako sú znaky zaručene prítomné vo vyššie uvedených opisoch. Pokusy o to majú nedefinované správanie, s veľmi reálnou možnosťou pádu aplikácie a výsledkami odpadov aj pri čítaní, a navyše veľkoobchodné dáta, poškodenie zásobníka a/alebo bezpečnostné zraniteľnosti pri zápise. Kedy sa tieto ukazovatele zneplatnia?

      Ak zavoláte nejakú členskú funkciu string, ktorá modifikuje string alebo rezervuje ďalšiu kapacitu, všetky hodnoty ukazovateľov vrátené predtým niektorou z uvedených metód sú zneplatnené. Tieto metódy môžete použiť znova, aby ste získali iný ukazovateľ. (Pravidlá sú rovnaké ako pre iterátory do string). Pozri tiež Ako získať platnosť ukazovateľa na znak aj po tom, čo x opustí rozsah alebo je ďalej modifikovaný nižšie.... Čo je teda lepšie použiť?

      Od C++11 používajte .c_str() pre dáta ASCIIZ a .data() pre "binárne" dáta (vysvetlené ďalej). V C++03 používajte .c_str(), pokiaľ si nie ste istí, že .data() je adekvátne, a uprednostnite .data() pred &x[0], pretože je'bezpečný pre prázdne reťazce.... ...snažte sa pochopiť program natoľko, aby ste mohli použiť data(), keď je to vhodné, inak sa pravdepodobne dopustíte ďalších chýb...

Znak ASCII NUL '\0' garantovaný funkciou .c_str() sa používa v mnohých funkciách ako strážna hodnota označujúca koniec relevantných a bezpečne prístupných údajov. To sa týka tak funkcií len pre jazyk C++, ako napríklad fstream::fstream(const char* filename, ...), ako aj funkcií zdieľaných s C, ako napríklad strchr() a printf(). Vzhľadom na to, že záruky C++03's .c_str()'s ohľadom na vrátený buffer sú nadmnožinou .data()'s, môžete vždy bezpečne použiť .c_str(), ale ľudia to niekedy nerobia, pretože:

  • Použitím .data() oznamujete ostatným programátorom čítajúcim zdrojový kód, že dáta nie sú ASCIIZ (skôr používate reťazec na uloženie bloku dát (ktorý niekedy ani nie je textový)), alebo že ho odovzdávate inej funkcii, ktorá s ním zaobchádza ako s blokom "binárnych" dát. Toto môže byť rozhodujúci poznatok, ktorý zabezpečí, že ďalší programátori' pri zmenách kódu budú s údajmi naďalej správne zaobchádzať.
  • Len v jazyku C++03: existuje'malá šanca, že vaša implementácia stringu bude musieť vykonať dodatočnú alokáciu pamäte a/alebo kopírovanie dát, aby pripravila buffer ukončený NUL Ako ďalšia rada, ak parametre funkcie'vyžadujú (const) char*, ale netrvajú na získaní x.size(), funkcia pravdepodobne potrebuje ASCIIZ vstup, takže .c_str() je dobrou voľbou (funkcia musí nejako vedieť, kde text končí, takže ak to'nie je samostatný parameter, môže to byť len konvencia ako length-prefix alebo sentinel alebo nejaká pevná očakávaná dĺžka). Ako získať ukazovateľ na znak platný aj po tom, čo x opustí rozsah alebo je ďalej modifikovaný

    Budete musieť kopírovať obsah reťazca x do novej oblasti pamäte mimo x. Táto externá vyrovnávacia pamäť môže byť na mnohých miestach, napríklad v inom stringu alebo v premennej znakového poľa, môže, ale nemusí mať inú životnosť ako x z dôvodu, že je v inom rozsahu (napr. v mennom priestore, globálnom, statickom, na halde, v zdieľanej pamäti, v súbore mapovanom na pamäť). Kopírovanie textu z premennej std::string x do nezávislého znakového poľa:

// 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 `&old_x[0]` to get a writable char* to old_x's 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 (e.g. 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's answer

// USING malloc/free HEAP MEMORY, MANUAL DEALLOC, NO INHERENT EXCEPTION SAFETY
char* y = strdup(x.c_str());
// use y...
free(y);

Ďalšie dôvody, prečo chcieť, aby sa z reťazca string vygeneroval znak char* alebo const char*

Takže vyššie ste videli, ako získať (const) char* a ako vytvoriť kópiu textu nezávislú od pôvodného stringu, ale čo s ním môžete robiť? Náhodný výber príkladov...

  • poskytnúť "C" kódu prístup k C++ stringu'textu, ako v printf("x is '%s'", x.c_str());
  • skopírovať text x'do vyrovnávacej pamäte určenej volajúcim funkcie (napr. strncpy(callers_buffer, callers_buffer_size, x.c_str())) alebo do prchavej pamäte používanej na vstupno-výstupné operácie zariadenia (napr. for (const char* p = x.c_str(); *p; ++p) *p_device = *p;)
  • pripojiť text x'k znakovému poľu, ktoré už obsahuje nejaký text ASCIIZ (napr. strcat(other_buffer, x.c_str())) - dávajte pozor, aby ste neprekročili buffer (v mnohých situáciách možno budete musieť použiť strncat)
  • vrátiť z funkcie const char* alebo char* (možno z historických dôvodov - klient'používa vaše existujúce API - alebo kvôli kompatibilite s C nechcete vrátiť std::string, ale chcete pre volajúceho niekde skopírovať dáta vášho `stringu')
    • dávajte pozor, aby ste nevrátili ukazovateľ, ktorý môže byť volajúcim dereferencovaný po tom, čo lokálna premenná string, na ktorú tento ukazovateľ ukazoval, opustila rozsah
    • niektoré projekty so zdieľanými objektmi skompilovanými/linkovanými pre rôzne implementácie std::string (napr. STLport a compiler-native) môžu odovzdávať údaje ako ASCIIZ, aby sa predišlo konfliktom
Tony Delroy
Tony Delroy
Edited answer 10 jún 2019 в 2:10
187
0
Artificial intelligence to parse product page
productapi.dev
Mark Ransom
Mark Ransom
7 december 2008 в 7:31
2008-12-07T19:31:50+00:00
Viac na
Zdroj
Upraviť
#8677293

Použite metódu .c_str() pre const char *.

Môžete použiť &mystring[0] na získanie ukazovateľa char *, ale je tu niekoľko háčikov: nemusíte získať reťazec ukončený nulou a nebudete môcť zmeniť veľkosť reťazca. Zvlášť si musíte dávať pozor, aby ste nepridávali znaky za koniec reťazca, inak dôjde k prekročeniu vyrovnávacej pamäte (a pravdepodobne k pádu).

Do C++11 neexistovala záruka, že všetky znaky budú súčasťou toho istého súvislého buffera, ale v praxi tak aj tak fungovali všetky známe implementácie std::string; pozri Ukazuje "&s[0]" na súvislé znaky v std::string?.

Všimnite si, že mnohé členské funkcie string prerozdelia vnútornú vyrovnávaciu pamäť a zrušia všetky uložené ukazovatele. Najlepšie je ich okamžite použiť a potom zahodiť.

 Community
Community
Edited answer 23 máj 2017 в 12:18
33
0
Pridať otázku
Kategórie
Všetky
Technológia
Kultúra / Rekreácia
Život / Umenie
Veda
Profesionálne
Obchod
Používatelia
Všetky
New
Popular
1
Inessa bu
Registered pred mesiacom
2
Denis Babushkin
Registered pred mesiacom
3
asakuno asakuno
Registered pred mesiacom
4
aldo salerno
Registered pred mesiacom
5
Анна Батицкая
Registered pred mesiacom
Artificial intelligence to parse product page
productapi.dev
DA
DE
EL
ES
FR
ID
IT
JA
KO
NL
NO
PT
RO
RU
SK
TR
ZH
© kzen.dev 2023
Zdroj
stackoverflow.com
na základe licencie cc by-sa 3.0 s uvedením autora