Zamiast: char * writable = new char [str.size () + 1]; Możesz użyć char writable [str.size () + 1]; Dzięki temu nie musisz się martwić usunięciem możliwości zapisu lub obsługi wyjątków.
7
Nie możesz użyć str.size (), chyba że rozmiar jest znany w czasie kompilacji, może również przepełnić twój stos, jeśli stała wartość rozmiaru jest ogromna.
paulm
1
char * wynik = strcpy ((char *) malloc (str. długość () + 1), str.c_str ());
cegprakash
7
@cegprakash strcpyi malloctak naprawdę nie są w języku C ++.
boycy
4
Nie, ale char* dest = new char[str.length() + 1]; std::copy(str.begin(), str.end(), dest)byłby bardziej idiomatyczny C ++. strcpy()i malloc()nie są złe lub problematyczne, ale wydaje się niespójne używanie łańcucha C ++ i narzędzi biblioteki C z odpowiednikami C ++ w tym samym bloku kodu.
boycy
Odpowiedzi:
1055
Jeśli chcesz tylko przekazać std::stringfunkcję, która potrzebuje const char*, możesz jej użyć
std::string str;constchar* c = str.c_str();
Jeśli chcesz uzyskać zapisywalną kopię char *, możesz to zrobić w ten sposób:
std::string str;char* writable =newchar[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 itdelete[] writable;
Edycja : Zauważ, że powyższe nie jest wyjątkowo bezpieczne. Jeśli coś między newpołączeniem a deletepołączeniem zostanie rzucone, nastąpi wyciek pamięci, ponieważ nic nie zadzwoni deleteautomatycznie. Istnieją dwa bezpośrednie sposoby rozwiązania tego problemu.
std::string str;
boost::scoped_array<char> writable(newchar[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 :: wektor
Jest to standardowy sposób (nie wymaga żadnej biblioteki zewnętrznej). Używasz std::vector, który całkowicie zarządza dla ciebie pamięcią.
std::string str;
std::vector<char> writable(str.begin(), str.end());
writable.push_back('\0');// get the char* using &writable[0] or &*writable.begin()
Po prostu użyj char * result = strdup (str.c_str ());
Jasper Bekkers,
63
mogłeś, ale strdup nie jest standardową funkcją ac lub c ++, pochodzi od posix :)
Johannes Schaub - litb
14
to, co prawdopodobnie wolałbym ogólnie, to std :: vector <char> writable (str.begin (), str.end ()); writable.push_back ('\ 0'); char * c = & zapisywalny [0];
Johannes Schaub - litb
17
std :: copy jest sposobem na zrobienie tego w c ++, bez potrzeby sięgania po wskaźnik łańcucha. Staram się unikać używania funkcji C tak bardzo, jak tylko mogę.
Johannes Schaub - litb
16
Począwszy od C ++ 17, std::string::data()teraz zwraca CharT*zamiast zamiast const CharT*. Dobrym pomysłem może być aktualizacja tej odpowiedzi :)
Rakete1111
192
Biorąc pod uwagę powiedz ...
std::string x ="hello";
Uzyskiwanie `char *` lub `const char *` z `string`
Jak uzyskać wskaźnik znaku, który jest prawidłowy, dopóki xpozostaje w zasięgu i nie jest dalej modyfikowany
C ++ 11 upraszcza rzeczy; następujące zapewniają dostęp do tego samego wewnętrznego bufora ciągów:
constchar* p_c_str = x.c_str();constchar* p_data = x.data();char* p_writable_data = x.data();// for non-const x from C++17 constchar* p_x0 =&x[0];char* p_x0_rw =&x[0];// compiles iff x is not const...
Wszystkie powyższe wskaźniki będą miały tę samą wartość - adres pierwszego znaku w buforze. Nawet pusty ciąg ma „pierwszy znak w buforze”, ponieważ C ++ 11 gwarantuje, że zawsze zachowa dodatkowy znak terminatora NUL / 0 po jawnie przypisanej zawartości ciągu (np. std::string("this\0that", 9)Będzie miał bufor "this\0that\0").
Biorąc pod uwagę którykolwiek z powyższych wskaźników:
char c = p[n];// valid for n <= x.size()// i.e. you can safely read the NUL at p[x.size()]
Tylko dla non- constpoint p_writable_datai od &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
Napisanie NUL gdzie indziej w ciągu nie zmienia string's size(); stringmogą zawierać dowolną liczbę wartości NUL - nie są traktowane przez std::string(tak samo jak w C ++ 03).
W C ++ 03 rzeczy były znacznie bardziej skomplikowane ( podkreślono kluczowe różnice ):
x.data()
wraca const char*do wewnętrznego bufora łańcucha, który nie był wymagany przez Standard do zakończenia z NUL (tzn. mogą wystąpić ['h', 'e', 'l', 'l', 'o']wartości niezainicjowane lub śmieci, z przypadkowym dostępem do nich o nieokreślonym zachowaniu ).
x.size()znaki są bezpieczne do odczytania, tzn. x[0]poprzezx[x.size() - 1]
w przypadku pustych ciągów masz gwarancję, że wskaźnik nie jest równy NULL, do którego można bezpiecznie dodać 0 (hurra!), ale nie powinieneś odrywać tego wskaźnika.
&x[0]
w przypadku pustych ciągów zachowanie to jest niezdefiniowane (21.3.4)
np. biorąc pod uwagę, f(const char* p, size_t n) { if (n == 0) return; ...whatever... }że nie wolno dzwonić, f(&x[0], x.size());kiedy x.empty()- po prostu użyj f(x.data(), ...).
w przeciwnym razie, zgodnie z, x.data()ale:
dla nie- constxdaje to constchar*wskaźnik niepowodujący; możesz zastąpić treść ciągu
x.c_str()
powraca const char*do reprezentacji wartości ASCIIZ (zakończonej przez NUL) (tj. [„h”, „e”, „l”, „l”, „o”, „\ 0”]).
chociaż niewiele, jeśli jakieś implementacje zdecydowały się to zrobić, standard C ++ 03 został sformułowany tak, aby umożliwić implementacji łańcucha swobodę tworzenia w locie odrębnego bufora zakończonego NUL , z potencjalnie nie zakończonego NUL bufora „odsłoniętego” przez ix.data()&x[0]
x.size() + 1 znaki są bezpieczne do odczytania.
gwarantowane bezpieczeństwo nawet dla pustych ciągów (['\ 0']).
Konsekwencje dostępu do zewnętrznych wskaźników prawnych
Niezależnie od tego, w jaki sposób uzyskasz wskaźnik, nie możesz uzyskać dostępu do pamięci dalej od wskaźnika niż znaki gwarantowane obecne w powyższych opisach. Próby tego mają nieokreślone zachowanie , z bardzo realną szansą na awarie aplikacji i śmieciowe wyniki nawet dla odczytów, a dodatkowo hurtową sprzedaż danych, uszkodzenie stosu i / lub luki w zabezpieczeniach zapisu.
Kiedy wskaźniki te zostaną unieważnione?
W przypadku wywołania stringfunkcji członkowskiej, która modyfikuje stringlub rezerwuje dodatkową pojemność, wszelkie wartości wskaźnika zwrócone wcześniej za pomocą dowolnej z powyższych metod zostaną unieważnione . Możesz użyć tych metod ponownie, aby uzyskać inny wskaźnik. (Zasady są takie same, jak dla iteratorów na strings).
Zobacz także Jak uzyskać poprawność wskaźnika znaku nawet po xopuszczeniu zasięgu lub dalszej modyfikacji poniżej ...
Którego lepiej użyć?
Od C ++ 11 używaj .c_str()danych ASCIIZ i danych .data()„binarnych” (wyjaśnione poniżej).
W C ++ 03, korzystanie .c_str()chyba pewne, że .data()jest odpowiednia, i wolą .data()nad &x[0]jak to jest bezpieczne dla pustych strunach ....
... postaraj się zrozumieć program na tyle, aby użyć go w data()razie potrzeby, w przeciwnym razie prawdopodobnie popełnisz inne błędy ...
Znak ASCII NUL „\ 0” gwarantowany przez .c_str()jest używany przez wiele funkcji jako wartość wartownika oznaczająca koniec odpowiednich i bezpiecznych danych. Dotyczy to zarówno funkcji C ++, takich jak say, jak fstream::fstream(const char* filename, ...)i funkcji współdzielonych z C, takich jak strchr()i printf().
Biorąc pod uwagę, .c_str()że gwarancje C ++ 03 dotyczące zwróconego bufora są super zestawem .data(), zawsze możesz bezpiecznie używać .c_str(), ale ludzie czasami nie, ponieważ:
używanie .data()komunikuje się innym programistom odczytującym kod źródłowy, że dane nie są ASCIIZ (raczej używasz ciągu do przechowywania bloku danych (który czasami nie jest nawet tekstowy)), lub że przekazujesz go do kolejna funkcja, która traktuje to jako blok danych „binarnych”. Może to być kluczowy wgląd w zapewnienie, że zmiany kodu innych programistów będą nadal poprawnie obsługiwać dane.
Tylko C ++ 03: istnieje niewielka szansa, że twoja stringimplementacja będzie musiała dokonać dodatkowej alokacji pamięci i / lub kopiowania danych, aby przygotować bufor zakończony NUL
Jako kolejna wskazówka, jeśli parametry funkcji wymagają ( const), char*ale nie nalegają na uzyskanie x.size(), funkcja prawdopodobnie wymaga wejścia ASCIIZ, więc .c_str()jest to dobry wybór (funkcja musi wiedzieć, gdzie tekst się kończy, więc jeśli nie jest oddzielnym parametrem może być tylko konwencja, taka jak prefiks długości lub wartownik lub niektóre ustalone oczekiwane długości).
Jak uzyskać poprawność wskaźnika znaku nawet po xopuszczeniu zasięgu lub dalszej modyfikacji
Musisz skopiować zawartość stringxdo nowego obszaru pamięci na zewnątrz x. Ten bufor zewnętrzny może znajdować się w wielu miejscach, takich jak inna stringzmienna lub tablica znaków, może mieć inny okres istnienia niż xw innym zakresie (np. Przestrzeń nazw, globalna, statyczna, sterty, pamięć współdzielona, plik odwzorowany w pamięci) .
Aby skopiować tekst z std::string xniezależnej tablicy znaków:
// 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) LENGTHchar* 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 SAFETYchar* y =newchar[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 SAFETYchar* y = strdup(x.c_str());// use y...
free(y);
Inne powody, aby chcieć char*lub const char*wygenerowane zstring
Powyżej widziałeś, jak uzyskać ( const) char*i jak zrobić kopię tekstu niezależną od oryginału string, ale co możesz z tym zrobić ? Losowe rozproszenie przykładów ...
daj kodowi „C” dostęp do stringtekstu C ++ , jak wprintf("x is '%s'", x.c_str());
skopiuj xtekst do bufora określonego przez program wywołujący twoją funkcję (np. strncpy(callers_buffer, callers_buffer_size, x.c_str())) lub pamięć ulotną używaną dla urządzeń I / O (np. for (const char* p = x.c_str(); *p; ++p) *p_device = *p;)
Dołącz xdydaktycznego tekst do tablicy znaków zawierający już jakiś tekst ASCIIZ (np strcat(other_buffer, x.c_str())) - uważać, by nie przekroczyć bufor (w wielu sytuacjach może zajść potrzeba użycia strncat)
zwraca a const char*lub char*z funkcji (być może z powodów historycznych - klient używa istniejącego API - lub ze względu na kompatybilność z C nie chcesz zwracać a std::string, ale chcesz skopiować stringdane gdzieś dla dzwoniącego)
uważaj, aby nie zwrócić wskaźnika, który może zostać odwołany przez wywołującego po stringzmiennej lokalnej , na którą wskazany wskaźnik opuścił zakres
niektóre projekty ze skompilowanymi / połączonymi obiektami dla różnych std::stringimplementacji (np. STLport i natywny dla kompilatora) mogą przekazywać dane jako ASCIIZ, aby uniknąć konfliktów
Niezłe. Innym powodem, aby chcieć char * (non const) jest praca z transmisją MPI. Wygląda ładniej, jeśli nie musisz kopiować tam i z powrotem. Osobiście zaoferowałbym ciąg znaków char * const. Stały wskaźnik, ale edytowalny ciąg. Chociaż mogło to mieć wpływ na niejawną konwersję z const char * na string ...
bartgol 30.10.14
33
Użyj .c_str()metody dla const char *.
Możesz użyć, &mystring[0]aby uzyskać char *wskaźnik, ale jest kilka gotcha: niekoniecznie otrzymasz ciąg zakończony zerami i nie będziesz w stanie zmienić jego rozmiaru. Należy szczególnie uważać, aby nie dodawać znaków poza koniec łańcucha, w przeciwnym razie wystąpi przepełnienie bufora (i prawdopodobna awaria).
Nie było żadnej gwarancji, że wszystkie znaki będą częścią tego samego ciągłego bufora aż do C ++ 11, ale w praktyce wszystkie znane implementacje std::stringdziałały w ten sposób; zobacz Czy „& s [0]” wskazuje na ciągłe znaki w std :: string? .
Zauważ, że wiele stringfunkcji składowych przenosi bufor wewnętrzny i unieważnia wszelkie zapisane wskaźniki. Najlepiej użyć ich natychmiast, a następnie odrzucić.
powinieneś zauważyć, że data () zwraca const char * :), co masz na myśli, to & str [0], która zwraca ciągły, ale nie konieczny ciąg zakończony zerą.
Johannes Schaub - litb
1
@litb, Argh! To właśnie dostaję za próbę szybkiego uzyskania odpowiedzi. Korzystałem z twojego rozwiązania w przeszłości, nie wiem, dlaczego nie była to pierwsza rzecz, która przyszła mi do głowy. Zredagowałem swoją odpowiedź.
Mark Ransom,
2
Technicznie, przechowywanie std :: string będzie ciągłe tylko w C ++ 0x.
MSalters,
1
@MSalters, dzięki - nie wiedziałem o tym. Trudno byłoby mi jednak znaleźć implementację, w której tak nie było.
Mark Ransom,
2
char * wynik = strcpy (malloc (str. długość () + 1), str.c_str ());
cegprakash
21
C ++ 17
C ++ 17 (nadchodzący standard) zmienia streszczenie szablonu, basic_stringdodając nieobciążone przeciążenie data():
charT* data() noexcept;
Zwraca: Wskaźnik p taki, że p + i == i operator dla każdego i w [0, size ()].
CharT const * od std::basic_string<CharT>
std::string const cstr ={"..."};charconst* p = cstr.data();// or .c_str()
CharT * od std::basic_string<CharT>
std::string str ={"..."};char* p = str.data();
C ++ 11
CharT const * od std::basic_string<CharT>
std::string str ={"..."};
str.c_str();
CharT * od std::basic_string<CharT>
Począwszy od C ++ 11 standard mówi:
Przedmioty podobne do znaków w basic_stringobiekcie należy przechowywać w sposób ciągły. Oznacza to, że dla każdego basic_stringprzedmiotu stożsamość &*(s.begin() + n) == &*s.begin() + nzachowuje wszystkie wartości tego nrodzaju 0 <= n < s.size().
Zwraca: *(begin() + pos)jeśli pos < size(), w innym przypadku odniesienie do obiektu typu CharTo wartości CharT(); wartości odniesienia nie można modyfikować.
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
Wywołałem klasę, DeepStringponieważ tworzy ona głęboką i unikalną kopię DeepStringistniejącego łańcucha (której nie można skopiować ).
Unikałbym tej konwencji nazewnictwa. c_str()używany przez stdjest skrótem dla „C-string”, a nie „const string” i str()zawsze zwraca a std::basic_string, not char*(na przykład std::stringstream::str())
bcrist
8
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());
wygląda fantazyjnie, ale naprawdę trudno zrozumieć ... Proste jest najlepsze IMO
Naeem A. Malik
4
strcpy (), malloc (), length () i c_str () są podstawowymi funkcjami i nie ma w tym nic trudnego. Po prostu przydzielanie pamięci i kopiowanie.
cegprakash
5
tak, funkcje są podstawowe, ale skręciłeś je i zgięłeś, aby wyglądały jak miska spaghetti lub potwór z jednej linijki :)
Naeem A. Malik,
4
Tak, funkcje są podstawowe, ale ... czy pamiętasz, kiedy zaczynasz zajmować się językiem programowania? Kilka linii do wyjaśnienia i naprawdę pomoże neoficie dowiedzieć się, dlaczego na przykład jest inna lub lepsza niż ta odpowiedź :)
Hastur
2
@cegprakash: Ilekroć istnieje malloc (), musi istnieć również free (). W przeciwnym razie kod wycieka pamięć, podobnie jak rozwiązanie w odpowiedzi. Przydzielanie pamięci bez wskazywania przynajmniej wymaganego zwolnienia jest złą praktyką w przypadku takich pytań.
Cześć, to, co napisałeś, zostało już powiedziane wiele razy, z dodatkowymi szczegółami, w innych odpowiedziach na pięcioletnie pytanie. Odpowiadanie na starsze pytania jest w porządku, ale tylko jeśli dodasz nowe informacje. W przeciwnym razie to tylko hałas.
strcpy
imalloc
tak naprawdę nie są w języku C ++.char* dest = new char[str.length() + 1]; std::copy(str.begin(), str.end(), dest)
byłby bardziej idiomatyczny C ++.strcpy()
imalloc()
nie są złe lub problematyczne, ale wydaje się niespójne używanie łańcucha C ++ i narzędzi biblioteki C z odpowiednikami C ++ w tym samym bloku kodu.Odpowiedzi:
Jeśli chcesz tylko przekazać
std::string
funkcję, która potrzebujeconst char*
, możesz jej użyćJeśli chcesz uzyskać zapisywalną kopię
char *
, możesz to zrobić w ten sposób:Edycja : Zauważ, że powyższe nie jest wyjątkowo bezpieczne. Jeśli coś między
new
połączeniem adelete
połączeniem zostanie rzucone, nastąpi wyciek pamięci, ponieważ nic nie zadzwonidelete
automatycznie. Istnieją dwa bezpośrednie sposoby rozwiązania tego problemu.boost :: scoped_array
boost::scoped_array
usunie dla ciebie pamięć po wyjściu poza zakres:std :: wektor
Jest to standardowy sposób (nie wymaga żadnej biblioteki zewnętrznej). Używasz
std::vector
, który całkowicie zarządza dla ciebie pamięcią.źródło
std::string::data()
teraz zwracaCharT*
zamiast zamiastconst CharT*
. Dobrym pomysłem może być aktualizacja tej odpowiedzi :)Biorąc pod uwagę powiedz ...
Uzyskiwanie `char *` lub `const char *` z `string`
Jak uzyskać wskaźnik znaku, który jest prawidłowy, dopóki
x
pozostaje w zasięgu i nie jest dalej modyfikowanyC ++ 11 upraszcza rzeczy; następujące zapewniają dostęp do tego samego wewnętrznego bufora ciągów:
Wszystkie powyższe wskaźniki będą miały tę samą wartość - adres pierwszego znaku w buforze. Nawet pusty ciąg ma „pierwszy znak w buforze”, ponieważ C ++ 11 gwarantuje, że zawsze zachowa dodatkowy znak terminatora NUL / 0 po jawnie przypisanej zawartości ciągu (np.
std::string("this\0that", 9)
Będzie miał bufor"this\0that\0"
).Biorąc pod uwagę którykolwiek z powyższych wskaźników:
Tylko dla non-
const
pointp_writable_data
i od&x[0]
:Napisanie NUL gdzie indziej w ciągu nie zmienia
string
'ssize()
;string
mogą zawierać dowolną liczbę wartości NUL - nie są traktowane przezstd::string
(tak samo jak w C ++ 03).W C ++ 03 rzeczy były znacznie bardziej skomplikowane ( podkreślono kluczowe różnice ):
x.data()
const char*
do wewnętrznego bufora łańcucha, który nie był wymagany przez Standard do zakończenia z NUL (tzn. mogą wystąpić['h', 'e', 'l', 'l', 'o']
wartości niezainicjowane lub śmieci, z przypadkowym dostępem do nich o nieokreślonym zachowaniu ).x.size()
znaki są bezpieczne do odczytania, tzn.x[0]
poprzezx[x.size() - 1]
&x[0]
f(const char* p, size_t n) { if (n == 0) return; ...whatever... }
że nie wolno dzwonić,f(&x[0], x.size());
kiedyx.empty()
- po prostu użyjf(x.data(), ...)
.x.data()
ale:const
x
daje toconst
char*
wskaźnik niepowodujący; możesz zastąpić treść ciągux.c_str()
const char*
do reprezentacji wartości ASCIIZ (zakończonej przez NUL) (tj. [„h”, „e”, „l”, „l”, „o”, „\ 0”]).x.data()
&x[0]
x.size()
+ 1 znaki są bezpieczne do odczytania.Konsekwencje dostępu do zewnętrznych wskaźników prawnych
Niezależnie od tego, w jaki sposób uzyskasz wskaźnik, nie możesz uzyskać dostępu do pamięci dalej od wskaźnika niż znaki gwarantowane obecne w powyższych opisach. Próby tego mają nieokreślone zachowanie , z bardzo realną szansą na awarie aplikacji i śmieciowe wyniki nawet dla odczytów, a dodatkowo hurtową sprzedaż danych, uszkodzenie stosu i / lub luki w zabezpieczeniach zapisu.
Kiedy wskaźniki te zostaną unieważnione?
W przypadku wywołania
string
funkcji członkowskiej, która modyfikujestring
lub rezerwuje dodatkową pojemność, wszelkie wartości wskaźnika zwrócone wcześniej za pomocą dowolnej z powyższych metod zostaną unieważnione . Możesz użyć tych metod ponownie, aby uzyskać inny wskaźnik. (Zasady są takie same, jak dla iteratorów nastring
s).Zobacz także Jak uzyskać poprawność wskaźnika znaku nawet po
x
opuszczeniu zasięgu lub dalszej modyfikacji poniżej ...Którego lepiej użyć?
Od C ++ 11 używaj
.c_str()
danych ASCIIZ i danych.data()
„binarnych” (wyjaśnione poniżej).W C ++ 03, korzystanie
.c_str()
chyba pewne, że.data()
jest odpowiednia, i wolą.data()
nad&x[0]
jak to jest bezpieczne dla pustych strunach ....... postaraj się zrozumieć program na tyle, aby użyć go w
data()
razie potrzeby, w przeciwnym razie prawdopodobnie popełnisz inne błędy ...Znak ASCII NUL „\ 0” gwarantowany przez
.c_str()
jest używany przez wiele funkcji jako wartość wartownika oznaczająca koniec odpowiednich i bezpiecznych danych. Dotyczy to zarówno funkcji C ++, takich jak say, jakfstream::fstream(const char* filename, ...)
i funkcji współdzielonych z C, takich jakstrchr()
iprintf()
.Biorąc pod uwagę,
.c_str()
że gwarancje C ++ 03 dotyczące zwróconego bufora są super zestawem.data()
, zawsze możesz bezpiecznie używać.c_str()
, ale ludzie czasami nie, ponieważ:.data()
komunikuje się innym programistom odczytującym kod źródłowy, że dane nie są ASCIIZ (raczej używasz ciągu do przechowywania bloku danych (który czasami nie jest nawet tekstowy)), lub że przekazujesz go do kolejna funkcja, która traktuje to jako blok danych „binarnych”. Może to być kluczowy wgląd w zapewnienie, że zmiany kodu innych programistów będą nadal poprawnie obsługiwać dane.string
implementacja będzie musiała dokonać dodatkowej alokacji pamięci i / lub kopiowania danych, aby przygotować bufor zakończony NULJako kolejna wskazówka, jeśli parametry funkcji wymagają (
const
),char*
ale nie nalegają na uzyskaniex.size()
, funkcja prawdopodobnie wymaga wejścia ASCIIZ, więc.c_str()
jest to dobry wybór (funkcja musi wiedzieć, gdzie tekst się kończy, więc jeśli nie jest oddzielnym parametrem może być tylko konwencja, taka jak prefiks długości lub wartownik lub niektóre ustalone oczekiwane długości).Jak uzyskać poprawność wskaźnika znaku nawet po
x
opuszczeniu zasięgu lub dalszej modyfikacjiMusisz skopiować zawartość
string
x
do nowego obszaru pamięci na zewnątrzx
. Ten bufor zewnętrzny może znajdować się w wielu miejscach, takich jak innastring
zmienna lub tablica znaków, może mieć inny okres istnienia niżx
w innym zakresie (np. Przestrzeń nazw, globalna, statyczna, sterty, pamięć współdzielona, plik odwzorowany w pamięci) .Aby skopiować tekst z
std::string x
niezależnej tablicy znaków:Inne powody, aby chcieć
char*
lubconst char*
wygenerowane zstring
Powyżej widziałeś, jak uzyskać (
const
)char*
i jak zrobić kopię tekstu niezależną od oryginałustring
, ale co możesz z tym zrobić ? Losowe rozproszenie przykładów ...string
tekstu C ++ , jak wprintf("x is '%s'", x.c_str());
x
tekst do bufora określonego przez program wywołujący twoją funkcję (np.strncpy(callers_buffer, callers_buffer_size, x.c_str())
) lub pamięć ulotną używaną dla urządzeń I / O (np.for (const char* p = x.c_str(); *p; ++p) *p_device = *p;
)x
dydaktycznego tekst do tablicy znaków zawierający już jakiś tekst ASCIIZ (npstrcat(other_buffer, x.c_str())
) - uważać, by nie przekroczyć bufor (w wielu sytuacjach może zajść potrzeba użyciastrncat
)const char*
lubchar*
z funkcji (być może z powodów historycznych - klient używa istniejącego API - lub ze względu na kompatybilność z C nie chcesz zwracać astd::string
, ale chcesz skopiowaćstring
dane gdzieś dla dzwoniącego)string
zmiennej lokalnej , na którą wskazany wskaźnik opuścił zakresstd::string
implementacji (np. STLport i natywny dla kompilatora) mogą przekazywać dane jako ASCIIZ, aby uniknąć konfliktówźródło
Użyj
.c_str()
metody dlaconst char *
.Możesz użyć,
&mystring[0]
aby uzyskaćchar *
wskaźnik, ale jest kilka gotcha: niekoniecznie otrzymasz ciąg zakończony zerami i nie będziesz w stanie zmienić jego rozmiaru. Należy szczególnie uważać, aby nie dodawać znaków poza koniec łańcucha, w przeciwnym razie wystąpi przepełnienie bufora (i prawdopodobna awaria).Nie było żadnej gwarancji, że wszystkie znaki będą częścią tego samego ciągłego bufora aż do C ++ 11, ale w praktyce wszystkie znane implementacje
std::string
działały w ten sposób; zobacz Czy „& s [0]” wskazuje na ciągłe znaki w std :: string? .Zauważ, że wiele
string
funkcji składowych przenosi bufor wewnętrzny i unieważnia wszelkie zapisane wskaźniki. Najlepiej użyć ich natychmiast, a następnie odrzucić.źródło
C ++ 17
C ++ 17 (nadchodzący standard) zmienia streszczenie szablonu,
basic_string
dodając nieobciążone przeciążeniedata()
:CharT const *
odstd::basic_string<CharT>
CharT *
odstd::basic_string<CharT>
C ++ 11
CharT const *
odstd::basic_string<CharT>
CharT *
odstd::basic_string<CharT>
Począwszy od C ++ 11 standard mówi:
Istnieją możliwe do oddzielenia sposoby uzyskania wskaźnika postaci niezmiennej.
1. Użyj ciągłego przechowywania C ++ 11
Zawodowiec
Cons
'\0'
nie ma być zmieniane / niekoniecznie częścią pamięci non-const.2. Użyj
std::vector<CharT>
Zawodowiec
Cons
3. Użyj,
std::array<CharT, N>
jeśliN
jest stała czasowa kompilacji (i wystarczająco mała)Zawodowiec
Cons
4. Przydział pamięci Raw z automatycznym usuwaniem pamięci
Zawodowiec
Cons
5. Przydział pamięci surowej z obsługą ręczną
Zawodowiec
Kon
źródło
Pracuję z interfejsem API z wieloma funkcjami dostępnymi jako wejście
char*
.Stworzyłem małą klasę, aby zmierzyć się z tego rodzaju problemem, zaimplementowałem idiom RAII.
I możesz użyć go jako:
Wywołałem klasę,
DeepString
ponieważ tworzy ona głęboką i unikalną kopięDeepString
istniejącego łańcucha (której nie można skopiować ).źródło
c_str()
używany przezstd
jest skrótem dla „C-string”, a nie „const string” istr()
zawsze zwraca astd::basic_string
, notchar*
(na przykładstd::stringstream::str()
)źródło
Zobacz to:
Pamiętaj jednak, że to zwróci a
const char *
.W przypadku a
char *
użyj przycisku,strcpy
aby skopiować go do innejchar
tablicy.źródło
Spróbuj tego
źródło