Chcę przekonwertować std :: string na typ danych char * lub char [] .
std::string str = "string";
char* chr = str;
Powoduje: „błąd: nie można przekonwertować 'std :: string' na 'char' ...” .
Jakie są dostępne metody, aby to zrobić?
Nie zamieni się automatycznie (dzięki Bogu). Musisz użyć tej metody, c_str()
aby uzyskać wersję ciągu C.
std::string str = "string";
const char *cstr = str.c_str();
Zauważ, że zwraca a const char *
; nie mogą zmienić ciąg C-styl zwrócony przez c_str()
. Jeśli chcesz go przetworzyć, musisz go najpierw skopiować:
std::string str = "string";
char *cstr = new char[str.length() + 1];
strcpy(cstr, str.c_str());
// do stuff
delete [] cstr;
Lub we współczesnym C ++:
std::vector<char> cstr(str.c_str(), str.c_str() + str.size() + 1);
c_str
całkowicie unikałby tego szaleństwa.vector
został wymyślony właśnie jako opakowanie dla tablic dynamicznych, więc nieużywanie go wydaje się w najlepszym razie straconą szansą, aw najgorszym naruszeniem ducha C ++.std::string
że automatycznie się skonwertuje), a następnie wyjaśniam, czego powinien użyć, używając krótkiej próbki kodu. Myśląc dalej, wyjaśniam również niektóre skutki uboczne korzystania z tej funkcji, z których jedną jest to, że nie możesz edytować zwracanego ciąguc_str()
. Moje błędne przykłady błędnie postrzegasz jako prawdziwy kod do rozwiązywania problemów, ale tak nie jest.std::vector<char>
).Więcej szczegółów tutaj i tutaj, ale możesz użyć
źródło
Gdybym potrzebował modyfikowalnej, surowej kopii zawartości łańcucha c ++, zrobiłbym to:
i później:
Dlaczego więc nie będę majstrować przy standardzie std :: vector lub new [] jak ktokolwiek inny? Ponieważ gdy potrzebuję zmiennego surowego łańcucha char * w stylu C, to dlatego, że chcę wywołać kod C, który zmienia łańcuch, a kod C zwalnia rzeczy za pomocą free () i przydziela za pomocą malloc () (strdup używa malloc) . Więc jeśli przekażę mój nieprzetworzony ciąg do funkcji X napisanej w C , może on mieć ograniczenie w argumencie, który musi przypisać na stercie (na przykład, jeśli funkcja może chcieć wywołać realloc dla parametru). Ale jest bardzo mało prawdopodobne, że spodziewałby się argumentu przypisanego (niektórym przedefiniowanym przez użytkownika) nowemu []!
źródło
strdup
pochodzi.(Ta odpowiedź dotyczy tylko C ++ 98).
Proszę nie używać surowego
char*
.źródło
vector<char>(str.c_str(), str.c_str() + str.size() + 1)
bez przypisywania wskaźnika char tymczasowego?std::basic_string<>::c_str()
jest ważna do momentustring
zmiany lub zniszczenia. Oznacza to również, że zwraca tę samą wartość przy kolejnych połączeniach, o ilestring
nie jest modyfikowany.vector
. A gdyby napisać kod bezpieczny dla wyjątków bez mechanizmu RAII (tj. Używając surowych wskaźników), złożoność kodu byłaby znacznie wyższa niż tego prostego jednowierszowego.vector
ma ogromne koszty ogólne i złożoność. Jeśli twoim wymaganiem jest, abyś miał zmienną tablicę char, to w rzeczywistości wektor znaków jest właściwie idealnym opakowaniem w C ++. Jeśli twoje wymaganie wymaga tylko wskaźnika const-char, po prostu użyjc_str()
i gotowe.Jeśli chcesz tylko ciąg w stylu C reprezentujący tę samą treść:
Jeśli chcesz łańcucha w stylu C z nową zawartością, jednym ze sposobów (biorąc pod uwagę, że nie znasz rozmiaru łańcucha w czasie kompilacji) jest alokacja dynamiczna:
Nie zapomnij o
delete[]
tym później.Jeśli zamiast tego chcesz mieć statycznie przydzieloną tablicę o ograniczonej długości:
std::string
nie dokonuje domyślnej konwersji na te typy z tego prostego powodu, że konieczność wykonania tego jest zwykle zapachem projektowym. Upewnij się, że naprawdę potrzebujesz.Jeśli zdecydowanie potrzebujesz
char*
, najlepszym sposobem jest prawdopodobnie:źródło
&str.front(), &str.back()
(które nie są obecne w C ++ 03) zamiast bardziej powszechnegostr.begin()
istr.end()
?str.begin()
, lub nawetstd::begin(str)
, iterator-jak? Nie wierzę, żestring
ma jakiś obowiązek bycia w ciągłej pamięcivector
, czy ma to?&back() + 1
, a nie&back()
Byłoby to lepsze jako komentarz do odpowiedzi bobobobo, ale nie mam za to przedstawiciela. Osiąga to samo, ale dzięki lepszym praktykom.
Chociaż inne odpowiedzi są przydatne, jeśli kiedykolwiek będziesz musiał przejść
std::string
nachar*
jawnie bez const,const_cast
to twój przyjaciel.Pamiętaj, że nie da ci to kopii danych; da ci wskaźnik do łańcucha. Zatem jeśli zmodyfikujesz element
chr
, zmodyfikujeszstr
.źródło
Zakładając, że potrzebujesz tylko łańcucha w stylu C, aby przekazać jako dane wejściowe:
źródło
Aby być ściśle pedantycznym, nie można „konwertować parametru std :: string na typ danych char * lub char [].”
Jak pokazały inne odpowiedzi, możesz skopiować zawartość std :: string do tablicy char lub utworzyć const char * do zawartości std :: string, abyś mógł uzyskać do niej dostęp w stylu „C” .
Jeśli próbujesz zmienić zawartość std :: string, typ std :: string ma wszystkie metody, aby zrobić wszystko, co może być potrzebne.
Jeśli próbujesz przekazać go do jakiejś funkcji, która przyjmuje char *, istnieje std :: string :: c_str ().
źródło
Dla kompletności nie zapomnij
std::string::copy()
.std::string::copy()
nie kończy się NUL. Jeśli musisz zapewnić terminator NUL do użycia w funkcjach ciągów C:źródło
Oto jeszcze jedna solidna wersja z
Protocol Buffer
źródło
if (str[str.length()-1] != 0) str.push_back(0)
Konwersja w stylu OOP
konwerter.hpp
konwerter.cpp
stosowanie
źródło
źródło
Alternatywnie można użyć wektorów, aby uzyskać zapisywalny znak *, jak pokazano poniżej;
źródło
Możesz to zrobić za pomocą iteratora.
Powodzenia.
źródło
Bezpieczna wersja odpowiedzi char * orlp przy użyciu unikalnego_ptr:
źródło
Aby uzyskać
const char *
zstd::string
użyciac_str()
funkcji członka:Aby uzyskać non-const
char *
z anstd::string
, możesz użyćdata()
funkcji członka, która zwraca wskaźnik non-const od C ++ 17:W starszych wersjach języka można użyć konstrukcji zakresu, aby skopiować ciąg do wektora, z którego można uzyskać wskaźnik niezmienny:
Ale uwaga: nie pozwoli to na modyfikację zawartego w nim ciągu
str
, tylko dane kopii można zmienić w ten sposób. Zauważ, że jest to szczególnie ważne w starszych wersjach tego językac_str()
, ponieważ w tamtych czasachstd::string
nie było gwarantowane, że zostanie zakończone zerowo, dopóki niec_str()
zostanie wywołane.źródło
To też zadziała
źródło