Alih-alih: char * writable = new char [str.size () + 1]; Anda dapat menggunakan char writable [str.size () + 1]; Maka Anda tidak perlu khawatir tentang menghapus penanganan yang dapat ditulis atau pengecualian.
7
Anda tidak dapat menggunakan str.size () kecuali ukurannya diketahui pada waktu kompilasi, juga ia mungkin meluap tumpukan Anda jika nilai ukuran tetapnya besar.
@cegprakash strcpydan mallocsebenarnya bukan cara C ++.
boycy
4
Tidak, tetapi char* dest = new char[str.length() + 1]; std::copy(str.begin(), str.end(), dest)C ++ akan lebih idiomatis. strcpy()dan malloc()tidak salah atau bermasalah, tetapi tampaknya tidak konsisten untuk menggunakan string C ++ dan fasilitas pustaka C dengan padanan C ++ dalam blok kode yang sama.
boycy
Jawaban:
1057
Jika Anda hanya ingin meneruskan std::stringke fungsi yang perlu const char*Anda dapat gunakan
std::string str;constchar* c = str.c_str();
Jika Anda ingin mendapatkan salinan yang dapat ditulisi char *, Anda dapat melakukannya dengan ini:
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;
Sunting : Perhatikan bahwa di atas tidak terkecuali aman. Jika ada sesuatu antara newpanggilan dan deletepanggilan yang dilemparkan, Anda akan membocorkan memori, karena tidak ada yang memanggil deleteAnda secara otomatis. Ada dua cara langsung untuk menyelesaikan ini.
boost :: scoped_array
boost::scoped_array akan menghapus memori untuk Anda setelah keluar dari ruang lingkup:
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 :: vektor
Ini adalah cara standar (tidak memerlukan perpustakaan eksternal). Anda menggunakan std::vector, yang sepenuhnya mengelola memori untuk Anda.
std::string str;
std::vector<char> writable(str.begin(), str.end());
writable.push_back('\0');// get the char* using &writable[0] or &*writable.begin()
Cukup gunakan char * result = strdup (str.c_str ());
Jasper Bekkers
63
Anda bisa, tetapi strdup bukan ac atau c ++ fungsi standar, itu dari posix :)
Johannes Schaub - litb
14
apa yang saya mungkin lebih suka umumnya adalah std :: vector <char> dapat ditulis (str.begin (), str.end ()); writable.push_back ('\ 0'); char * c = & dapat ditulis [0];
Johannes Schaub - litb
17
std :: copy adalah cara c ++ untuk melakukan ini, tanpa harus mendapatkan penunjuk string. Saya mencoba untuk menghindari menggunakan fungsi C sebanyak yang saya bisa.
Johannes Schaub - litb
16
Pada C ++ 17, std::string::data()sekarang mengembalikan a CharT*bukan const CharT*. Mungkin ide yang bagus untuk memperbarui jawaban ini :)
Rakete1111
192
Diberikan katakan ...
std::string x ="hello";
Mendapatkan `char *` atau `const char *` dari `string`
Cara mendapatkan penunjuk karakter yang valid sambil xtetap dalam cakupan dan tidak dimodifikasi lebih lanjut
C ++ 11 menyederhanakan banyak hal; semua yang berikut memberikan akses ke buffer string internal yang sama:
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...
Semua petunjuk di atas akan memiliki nilai yang sama - alamat karakter pertama di buffer. Bahkan string kosong memiliki "karakter pertama dalam buffer", karena C ++ 11 menjamin untuk selalu menyimpan karakter terminator NUL / 0 tambahan setelah konten string yang ditetapkan secara eksplisit (mis. std::string("this\0that", 9)Akan memiliki holding buffer "this\0that\0").
Diberikan salah satu petunjuk di atas:
char c = p[n];// valid for n <= x.size()// i.e. you can safely read the NUL at p[x.size()]
Hanya untuk yang bukan constpenunjuk p_writable_datadan dari &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
Menulis NUL di tempat lain dalam string tidak mengubah string's size(); stringDiijinkan mengandung sejumlah NUL - mereka tidak diberi perlakuan khusus oleh std::string(sama dalam C ++ 03).
Di C ++ 03 , hal-hal yang jauh lebih rumit (perbedaan utama disorot ):
x.data()
kembali const char*ke buffer internal string yang tidak diperlukan oleh Standar untuk menyimpulkan dengan NUL (yaitu mungkin ['h', 'e', 'l', 'l', 'o']diikuti oleh nilai-nilai tidak diinisialisasi atau sampah, dengan akses tidak disengaja yang memiliki perilaku yang tidak ditentukan ).
x.size()karakter aman untuk dibaca, yaitu x[0]melaluix[x.size() - 1]
untuk string kosong, Anda dijamin beberapa pointer NULL yang 0 dapat ditambahkan dengan aman (hore!), tetapi Anda tidak boleh dereferensi pointer itu.
&x[0]
untuk string kosong ini memiliki perilaku yang tidak jelas (21.3.4)
mis. diberikan f(const char* p, size_t n) { if (n == 0) return; ...whatever... }Anda tidak harus menelepon f(&x[0], x.size());kapan x.empty()- gunakan saja f(x.data(), ...).
jika tidak, sesuai x.data()tetapi:
untuk non- constxini menghasilkan non- constchar*pointer; Anda dapat menimpa konten string
x.c_str()
kembali const char*ke representasi ASCIIZ (diakhiri NUL) dari nilai (yaitu ['h', 'e', 'l', 'l', 'o', '\ 0']).
meskipun sedikit jika ada implementasi yang memilih untuk melakukannya, Standar C ++ 03 diucapkan untuk memungkinkan implementasi string kebebasan untuk membuat buffer NUL-dihentikan dengan cepat , dari buffer yang berpotensi non-NUL yang diakhiri oleh "terkena" oleh x.data()dan&x[0]
x.size() +1 karakter aman untuk dibaca.
dijamin aman bahkan untuk string kosong (['\ 0']).
Konsekuensi mengakses indeks hukum luar
Dengan cara apa pun Anda mendapatkan pointer, Anda tidak boleh mengakses memori lebih jauh dari pointer daripada karakter dijamin hadir dalam deskripsi di atas. Upaya untuk melakukannya memiliki perilaku yang tidak terdefinisi , dengan kemungkinan crash aplikasi dan hasil sampah yang sangat nyata bahkan untuk dibaca, dan juga data grosir, tumpukan korupsi dan / atau kerentanan keamanan untuk penulisan.
Kapan pointer tersebut dibatalkan?
Jika Anda memanggil beberapa stringfungsi anggota yang memodifikasi stringatau cadangan kapasitas lebih lanjut, nilai pointer apa pun yang dikembalikan sebelumnya dengan salah satu metode di atas tidak valid . Anda dapat menggunakan metode itu lagi untuk mendapatkan pointer lain. (Aturannya sama dengan iterator ke strings).
Lihat juga Cara mendapatkan penunjuk karakter yang valid bahkan setelah xmeninggalkan cakupan atau dimodifikasi lebih lanjut di bawah ....
Jadi, mana yang lebih baik untuk digunakan?
Dari C ++ 11, gunakan .c_str()untuk data ASCIIZ, dan .data()untuk data "biner" (dijelaskan lebih lanjut di bawah).
Dalam C ++ 03, penggunaan .c_str()kecuali tertentu yang .data()memadai, dan lebih memilih .data()lebih &x[0]seperti itu aman untuk string kosong ....
... cobalah untuk memahami program yang cukup untuk digunakan data()saat yang tepat, atau Anda mungkin akan membuat kesalahan lain ...
Karakter ASCII NUL '\ 0' yang dijamin oleh .c_str()digunakan oleh banyak fungsi sebagai nilai sentinel yang menunjukkan akhir data yang relevan dan aman untuk diakses. Ini berlaku untuk C ++ - hanya fungsi seperti fungsi say fstream::fstream(const char* filename, ...)dan shared-with-C seperti strchr(), dan printf().
Mengingat .c_str()jaminan C ++ 03 tentang buffer yang dikembalikan adalah set super .data(), Anda selalu dapat menggunakan dengan aman .c_str(), tetapi orang terkadang tidak melakukannya karena:
menggunakan .data()komunikasi dengan pemrogram lain yang membaca kode sumber bahwa data tersebut bukan ASCIIZ (melainkan, Anda menggunakan string untuk menyimpan blok data (yang kadang-kadang bahkan tidak benar-benar tekstual)), atau Anda meneruskannya ke fungsi lain yang memperlakukannya sebagai blok data "biner". Ini bisa menjadi wawasan penting dalam memastikan bahwa perubahan kode programmer lain terus menangani data dengan benar.
Hanya C ++ 03: ada sedikit peluang bahwa stringimplementasi Anda perlu melakukan alokasi memori tambahan dan / atau menyalin data untuk menyiapkan buffer NUL yang dihentikan
Sebagai petunjuk lebih lanjut, jika parameter fungsi memerlukan ( const) char*tetapi tidak bersikeras untuk mendapatkannya x.size(), fungsi tersebut mungkin membutuhkan input ASCIIZ, jadi .c_str()ini adalah pilihan yang baik (fungsi perlu tahu di mana teks berakhir, entah bagaimana, jadi jika tidak parameter yang terpisah hanya dapat berupa konvensi seperti awalan panjang atau sentinel atau panjang yang diharapkan tetap).
Cara mendapatkan penunjuk karakter yang valid bahkan setelah xmeninggalkan ruang lingkup atau dimodifikasi lebih lanjut
Anda harus menyalin konten stringxke area memori baru di luar x. Buffer eksternal ini dapat berada di banyak tempat seperti stringvariabel array karakter atau lainnya , mungkin atau mungkin tidak memiliki masa hidup yang berbeda daripada xkarena berada dalam ruang lingkup yang berbeda (mis. Namespace, global, statis, tumpukan, memori bersama, memori yang dipetakan file) .
Untuk menyalin teks dari std::string xke dalam array karakter independen:
// 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);
Alasan lain untuk menginginkan char*atau const char*dihasilkan daristring
Jadi, di atas Anda telah melihat cara mendapatkan ( const) char*, dan cara membuat salinan teks yang independen dari yang asli string, tetapi apa yang dapat Anda lakukan dengannya? Sebuah contoh acak ...
beri "C" akses kode ke stringteks C ++ , seperti padaprintf("x is '%s'", x.c_str());
menyalin xteks ke buffer yang ditentukan oleh pemanggil fungsi Anda (mis. strncpy(callers_buffer, callers_buffer_size, x.c_str())), atau memori yang mudah menguap digunakan untuk I / O perangkat (mis. for (const char* p = x.c_str(); *p; ++p) *p_device = *p;)
tambahkan xteks ke array karakter yang sudah mengandung beberapa teks ASCIIZ (mis. strcat(other_buffer, x.c_str())) - hati-hati jangan sampai menyerbu buffer (dalam banyak situasi Anda mungkin perlu menggunakan strncat)
mengembalikan sebuah const char*atau char*dari suatu fungsi (mungkin karena alasan historis - klien menggunakan API Anda yang ada - atau untuk kompatibilitas C Anda tidak ingin mengembalikan std::string, tetapi ingin menyalin stringdata Anda di suatu tempat untuk penelepon)
hati-hati untuk tidak mengembalikan pointer yang mungkin ditereferensi oleh pemanggil setelah stringvariabel lokal yang menunjuk pointer telah meninggalkan ruang lingkup
beberapa proyek dengan objek bersama dikompilasi / ditautkan untuk std::stringimplementasi yang berbeda (mis. STLport dan compiler-native) dapat meneruskan data sebagai ASCIIZ untuk menghindari konflik
Bagus Alasan lain untuk menginginkan char * (non const) adalah untuk beroperasi dengan siaran MPI. Ini terlihat lebih bagus jika Anda tidak perlu menyalin bolak-balik. Saya akan secara pribadi menawarkan rajutan char * const ke string. Pointer Const, tetapi string yang dapat diedit. Meskipun mungkin telah mengacaukan konversi implisit dari const char * ke string ...
bartgol
33
Gunakan .c_str()metode untuk const char *.
Anda dapat menggunakan &mystring[0]untuk mendapatkan char *pointer, tetapi ada beberapa gotcha: Anda tidak perlu mendapatkan string yang diakhiri nol, dan Anda tidak akan dapat mengubah ukuran string. Anda terutama harus berhati-hati untuk tidak menambahkan karakter melewati akhir string atau Anda akan mendapatkan buffer overrun (dan kemungkinan crash).
Tidak ada jaminan bahwa semua karakter akan menjadi bagian dari buffer yang bersebelahan yang sama hingga C ++ 11, tetapi dalam praktiknya semua implementasi yang diketahui std::stringtetap bekerja seperti itu; lihat Apakah “& s [0]” menunjuk ke karakter yang berdekatan di std :: string? .
Perhatikan bahwa banyak stringfungsi anggota akan merealokasi buffer internal dan membatalkan semua petunjuk yang mungkin telah Anda simpan. Cara terbaik untuk menggunakannya segera dan kemudian buang.
Anda harus mencatat bahwa data () mengembalikan const char * :) yang Anda maksud adalah & str [0], yang mengembalikan sebuah string yang diakhiri, tetapi bukan necassary null.
Johannes Schaub - litb
1
@ litb, Argh! Itulah yang saya dapat karena mencoba memberikan jawaban cepat. Saya telah menggunakan solusi Anda di masa lalu, tidak tahu mengapa itu bukan hal pertama yang terlintas dalam pikiran. Saya sudah mengedit jawaban saya.
Mark Ransom
2
Secara teknis, penyimpanan std :: string hanya bersebelahan dalam C ++ 0x.
MSalters
1
@Malters, terima kasih - saya tidak tahu itu. Saya akan sulit sekali menemukan implementasi di mana bukan itu masalahnya.
C ++ 17 (standar mendatang) mengubah sinopsis templat dengan basic_stringmenambahkan kelebihan non const data():
charT* data() noexcept;
Pengembalian: Pointer p sehingga p + i == & operator untuk setiap i di [0, size ()].
CharT const * dari std::basic_string<CharT>
std::string const cstr ={"..."};charconst* p = cstr.data();// or .c_str()
CharT * dari std::basic_string<CharT>
std::string str ={"..."};char* p = str.data();
C ++ 11
CharT const * dari std::basic_string<CharT>
std::string str ={"..."};
str.c_str();
CharT * dari std::basic_string<CharT>
Dari C ++ 11 dan seterusnya, standar mengatakan:
Objek char-like dalam basic_stringobjek harus disimpan secara berdekatan. Artinya, untuk basic_stringobjek apa pun s, identitas &*(s.begin() + n) == &*s.begin() + nharus berlaku untuk semua nilai nsedemikian rupa 0 <= n < s.size().
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
Saya telah memanggil kelas DeepStringkarena membuat salinan yang dalam dan unik ( DeepStringtidak dapat disalin) dari string yang ada.
Saya akan menghindari konvensi penamaan ini. c_str()seperti yang digunakan oleh stdadalah singkatan untuk "C-string" bukan "const string" dan str()selalu mengembalikan a std::basic_string, tidak char*(misalnya std::stringstream::str())
bcrist
8
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());
terlihat mewah tetapi sangat sulit untuk dipahami ... Sederhana adalah IMO terbaik
Naeem A. Malik
4
strcpy (), malloc (), length () dan c_str () adalah fungsi dasar dan tidak ada yang sulit dalam hal ini. Hanya mengalokasikan memori dan menyalin.
cegprakash
5
ya fungsinya dasar tetapi Anda telah memelintir dan membengkokkannya agar terlihat seperti semangkuk spageti atau satu liner monster Frankenstein :)
Naeem A. Malik
4
Ya, fungsinya dasar tetapi ... apakah Anda ingat ketika Anda mulai berurusan dengan bahasa pemrograman? Beberapa baris lebih banyak untuk dijelaskan dan itu akan sangat membantu orang baru untuk belajar mengapa misalnya berbeda atau lebih baik daripada jawaban ini :)
Hastur
2
@cegprakash: Setiap kali ada malloc (), harus ada yang gratis (). Kalau tidak, kodenya bocor memori, dan begitu pula solusi dalam jawaban Anda. Mengalokasikan ingatan tanpa setidaknya mengisyaratkan kepada alokasi yang diperlukan adalah praktik buruk untuk pertanyaan seperti itu.
Hai, apa yang Anda posting telah dikatakan beberapa kali, dengan lebih detail, dalam jawaban lain untuk pertanyaan berusia 5 tahun. Tidak apa-apa untuk menjawab pertanyaan lama, tetapi hanya jika Anda menambahkan informasi baru. Kalau tidak, itu hanya kebisingan.
strcpy
danmalloc
sebenarnya bukan cara C ++.char* dest = new char[str.length() + 1]; std::copy(str.begin(), str.end(), dest)
C ++ akan lebih idiomatis.strcpy()
danmalloc()
tidak salah atau bermasalah, tetapi tampaknya tidak konsisten untuk menggunakan string C ++ dan fasilitas pustaka C dengan padanan C ++ dalam blok kode yang sama.Jawaban:
Jika Anda hanya ingin meneruskan
std::string
ke fungsi yang perluconst char*
Anda dapat gunakanJika Anda ingin mendapatkan salinan yang dapat ditulisi
char *
, Anda dapat melakukannya dengan ini:Sunting : Perhatikan bahwa di atas tidak terkecuali aman. Jika ada sesuatu antara
new
panggilan dandelete
panggilan yang dilemparkan, Anda akan membocorkan memori, karena tidak ada yang memanggildelete
Anda secara otomatis. Ada dua cara langsung untuk menyelesaikan ini.boost :: scoped_array
boost::scoped_array
akan menghapus memori untuk Anda setelah keluar dari ruang lingkup:std :: vektor
Ini adalah cara standar (tidak memerlukan perpustakaan eksternal). Anda menggunakan
std::vector
, yang sepenuhnya mengelola memori untuk Anda.sumber
std::string::data()
sekarang mengembalikan aCharT*
bukanconst CharT*
. Mungkin ide yang bagus untuk memperbarui jawaban ini :)Diberikan katakan ...
Mendapatkan `char *` atau `const char *` dari `string`
Cara mendapatkan penunjuk karakter yang valid sambil
x
tetap dalam cakupan dan tidak dimodifikasi lebih lanjutC ++ 11 menyederhanakan banyak hal; semua yang berikut memberikan akses ke buffer string internal yang sama:
Semua petunjuk di atas akan memiliki nilai yang sama - alamat karakter pertama di buffer. Bahkan string kosong memiliki "karakter pertama dalam buffer", karena C ++ 11 menjamin untuk selalu menyimpan karakter terminator NUL / 0 tambahan setelah konten string yang ditetapkan secara eksplisit (mis.
std::string("this\0that", 9)
Akan memiliki holding buffer"this\0that\0"
).Diberikan salah satu petunjuk di atas:
Hanya untuk yang bukan
const
penunjukp_writable_data
dan dari&x[0]
:Menulis NUL di tempat lain dalam string tidak mengubah
string
'ssize()
;string
Diijinkan mengandung sejumlah NUL - mereka tidak diberi perlakuan khusus olehstd::string
(sama dalam C ++ 03).Di C ++ 03 , hal-hal yang jauh lebih rumit (perbedaan utama disorot ):
x.data()
const char*
ke buffer internal string yang tidak diperlukan oleh Standar untuk menyimpulkan dengan NUL (yaitu mungkin['h', 'e', 'l', 'l', 'o']
diikuti oleh nilai-nilai tidak diinisialisasi atau sampah, dengan akses tidak disengaja yang memiliki perilaku yang tidak ditentukan ).x.size()
karakter aman untuk dibaca, yaitux[0]
melaluix[x.size() - 1]
&x[0]
f(const char* p, size_t n) { if (n == 0) return; ...whatever... }
Anda tidak harus meneleponf(&x[0], x.size());
kapanx.empty()
- gunakan sajaf(x.data(), ...)
.x.data()
tetapi:const
x
ini menghasilkan non-const
char*
pointer; Anda dapat menimpa konten stringx.c_str()
const char*
ke representasi ASCIIZ (diakhiri NUL) dari nilai (yaitu ['h', 'e', 'l', 'l', 'o', '\ 0']).x.data()
dan&x[0]
x.size()
+1 karakter aman untuk dibaca.Konsekuensi mengakses indeks hukum luar
Dengan cara apa pun Anda mendapatkan pointer, Anda tidak boleh mengakses memori lebih jauh dari pointer daripada karakter dijamin hadir dalam deskripsi di atas. Upaya untuk melakukannya memiliki perilaku yang tidak terdefinisi , dengan kemungkinan crash aplikasi dan hasil sampah yang sangat nyata bahkan untuk dibaca, dan juga data grosir, tumpukan korupsi dan / atau kerentanan keamanan untuk penulisan.
Kapan pointer tersebut dibatalkan?
Jika Anda memanggil beberapa
string
fungsi anggota yang memodifikasistring
atau cadangan kapasitas lebih lanjut, nilai pointer apa pun yang dikembalikan sebelumnya dengan salah satu metode di atas tidak valid . Anda dapat menggunakan metode itu lagi untuk mendapatkan pointer lain. (Aturannya sama dengan iterator kestring
s).Lihat juga Cara mendapatkan penunjuk karakter yang valid bahkan setelah
x
meninggalkan cakupan atau dimodifikasi lebih lanjut di bawah ....Jadi, mana yang lebih baik untuk digunakan?
Dari C ++ 11, gunakan
.c_str()
untuk data ASCIIZ, dan.data()
untuk data "biner" (dijelaskan lebih lanjut di bawah).Dalam C ++ 03, penggunaan
.c_str()
kecuali tertentu yang.data()
memadai, dan lebih memilih.data()
lebih&x[0]
seperti itu aman untuk string kosong ....... cobalah untuk memahami program yang cukup untuk digunakan
data()
saat yang tepat, atau Anda mungkin akan membuat kesalahan lain ...Karakter ASCII NUL '\ 0' yang dijamin oleh
.c_str()
digunakan oleh banyak fungsi sebagai nilai sentinel yang menunjukkan akhir data yang relevan dan aman untuk diakses. Ini berlaku untuk C ++ - hanya fungsi seperti fungsi sayfstream::fstream(const char* filename, ...)
dan shared-with-C sepertistrchr()
, danprintf()
.Mengingat
.c_str()
jaminan C ++ 03 tentang buffer yang dikembalikan adalah set super.data()
, Anda selalu dapat menggunakan dengan aman.c_str()
, tetapi orang terkadang tidak melakukannya karena:.data()
komunikasi dengan pemrogram lain yang membaca kode sumber bahwa data tersebut bukan ASCIIZ (melainkan, Anda menggunakan string untuk menyimpan blok data (yang kadang-kadang bahkan tidak benar-benar tekstual)), atau Anda meneruskannya ke fungsi lain yang memperlakukannya sebagai blok data "biner". Ini bisa menjadi wawasan penting dalam memastikan bahwa perubahan kode programmer lain terus menangani data dengan benar.string
implementasi Anda perlu melakukan alokasi memori tambahan dan / atau menyalin data untuk menyiapkan buffer NUL yang dihentikanSebagai petunjuk lebih lanjut, jika parameter fungsi memerlukan (
const
)char*
tetapi tidak bersikeras untuk mendapatkannyax.size()
, fungsi tersebut mungkin membutuhkan input ASCIIZ, jadi.c_str()
ini adalah pilihan yang baik (fungsi perlu tahu di mana teks berakhir, entah bagaimana, jadi jika tidak parameter yang terpisah hanya dapat berupa konvensi seperti awalan panjang atau sentinel atau panjang yang diharapkan tetap).Cara mendapatkan penunjuk karakter yang valid bahkan setelah
x
meninggalkan ruang lingkup atau dimodifikasi lebih lanjutAnda harus menyalin konten
string
x
ke area memori baru di luarx
. Buffer eksternal ini dapat berada di banyak tempat sepertistring
variabel array karakter atau lainnya , mungkin atau mungkin tidak memiliki masa hidup yang berbeda daripadax
karena berada dalam ruang lingkup yang berbeda (mis. Namespace, global, statis, tumpukan, memori bersama, memori yang dipetakan file) .Untuk menyalin teks dari
std::string x
ke dalam array karakter independen:Alasan lain untuk menginginkan
char*
atauconst char*
dihasilkan daristring
Jadi, di atas Anda telah melihat cara mendapatkan (
const
)char*
, dan cara membuat salinan teks yang independen dari yang aslistring
, tetapi apa yang dapat Anda lakukan dengannya? Sebuah contoh acak ...string
teks C ++ , seperti padaprintf("x is '%s'", x.c_str());
x
teks ke buffer yang ditentukan oleh pemanggil fungsi Anda (mis.strncpy(callers_buffer, callers_buffer_size, x.c_str())
), atau memori yang mudah menguap digunakan untuk I / O perangkat (mis.for (const char* p = x.c_str(); *p; ++p) *p_device = *p;
)x
teks ke array karakter yang sudah mengandung beberapa teks ASCIIZ (mis.strcat(other_buffer, x.c_str())
) - hati-hati jangan sampai menyerbu buffer (dalam banyak situasi Anda mungkin perlu menggunakanstrncat
)const char*
atauchar*
dari suatu fungsi (mungkin karena alasan historis - klien menggunakan API Anda yang ada - atau untuk kompatibilitas C Anda tidak ingin mengembalikanstd::string
, tetapi ingin menyalinstring
data Anda di suatu tempat untuk penelepon)string
variabel lokal yang menunjuk pointer telah meninggalkan ruang lingkupstd::string
implementasi yang berbeda (mis. STLport dan compiler-native) dapat meneruskan data sebagai ASCIIZ untuk menghindari konfliksumber
Gunakan
.c_str()
metode untukconst char *
.Anda dapat menggunakan
&mystring[0]
untuk mendapatkanchar *
pointer, tetapi ada beberapa gotcha: Anda tidak perlu mendapatkan string yang diakhiri nol, dan Anda tidak akan dapat mengubah ukuran string. Anda terutama harus berhati-hati untuk tidak menambahkan karakter melewati akhir string atau Anda akan mendapatkan buffer overrun (dan kemungkinan crash).Tidak ada jaminan bahwa semua karakter akan menjadi bagian dari buffer yang bersebelahan yang sama hingga C ++ 11, tetapi dalam praktiknya semua implementasi yang diketahui
std::string
tetap bekerja seperti itu; lihat Apakah “& s [0]” menunjuk ke karakter yang berdekatan di std :: string? .Perhatikan bahwa banyak
string
fungsi anggota akan merealokasi buffer internal dan membatalkan semua petunjuk yang mungkin telah Anda simpan. Cara terbaik untuk menggunakannya segera dan kemudian buang.sumber
C ++ 17
C ++ 17 (standar mendatang) mengubah sinopsis templat dengan
basic_string
menambahkan kelebihan non constdata()
:CharT const *
daristd::basic_string<CharT>
CharT *
daristd::basic_string<CharT>
C ++ 11
CharT const *
daristd::basic_string<CharT>
CharT *
daristd::basic_string<CharT>
Dari C ++ 11 dan seterusnya, standar mengatakan:
Ada beberapa cara yang memungkinkan untuk mendapatkan pointer karakter non const.
1. Gunakan penyimpanan C ++ 11 yang berdekatan
Pro
Cons
'\0'
tidak boleh diubah / tidak harus bagian dari memori non-const.2. Gunakan
std::vector<CharT>
Pro
Cons
3. Gunakan
std::array<CharT, N>
jikaN
kompilasi waktu konstan (dan cukup kecil)Pro
Cons
4. Alokasi memori mentah dengan penghapusan penyimpanan otomatis
Pro
Cons
5. Alokasi memori mentah dengan penanganan manual
Pro
Menipu
sumber
Saya bekerja dengan API dengan banyak fungsi dapatkan sebagai input a
char*
.Saya telah membuat kelas kecil untuk menghadapi masalah semacam ini, saya telah mengimplementasikan idiom RAII.
Dan Anda dapat menggunakannya sebagai:
Saya telah memanggil kelas
DeepString
karena membuat salinan yang dalam dan unik (DeepString
tidak dapat disalin) dari string yang ada.sumber
c_str()
seperti yang digunakan olehstd
adalah singkatan untuk "C-string" bukan "const string" danstr()
selalu mengembalikan astd::basic_string
, tidakchar*
(misalnyastd::stringstream::str()
)sumber
Lihat saja ini:
Namun, perhatikan bahwa ini akan mengembalikan a
const char *
.Untuk a
char *
, gunakanstrcpy
untuk menyalinnya kechar
array lain .sumber
Coba ini
sumber