Bagaimana saya bisa mengkonversi sebuah std::string
ke char*
atau const char*
?
Jika anda hanya ingin lulus std::string
untuk fungsi yang membutuhkan const char*
anda dapat menggunakan
std::string str;
const char * c = str.c_str();
Jika anda ingin mendapatkan ditulisi, seperti char *
, anda bisa melakukan itu dengan ini:
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: Perhatikan bahwa di atas tidak terkecuali aman. Jika apa-apa antara baru
dan delete
call melempar, anda akan kebocoran memori, karena tidak ada yang akan memanggil hapus
untuk anda secara otomatis. Ada dua cara-cara langsung untuk memecahkan masalah ini.
boost::scoped_array
akan menghapus memori anda pada saat akan keluar dari ruang lingkup:
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
Ini adalah cara standar (tidak memerlukan library eksternal). Anda gunakan std::vektor
, yang benar-benar 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()
Mengingat mengatakan...
std::string x = "hello";
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...
Semua petunjuk di atas akan terus sama nilai - alamat dari karakter pertama dalam buffer. Bahkan string kosong memiliki "karakter pertama dalam buffer", karena C++11 jaminan untuk selalu menjaga ekstra NUL/0 terminator karakter setelah ditetapkan secara tegas string konten (misalnya std::string("\0that", 9)
akan memiliki penyangga memegang "\0that\0"
).
Mengingat semua 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 non-const
pointer p_writable_data
dan 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 tidak mengubah string
's size()
; string
's yang diperbolehkan untuk mengandung jumlah NULs - mereka yang tidak diberikan perlakuan khusus oleh std::string
(sama di C++03).
Di C++03, hal-hal yang jauh lebih rumit (perbedaan utama disorot):
x.data()
const char*
string's internal buffer yang bukan't yang dibutuhkan oleh Standar untuk menyimpulkan dengan NUL (yaitu mungkin ['h', 'e', 'l', 'l', 'o']
diikuti oleh uninitialised atau nilai sampah, dengan tidak disengaja mengakses dalamnya memiliki perilaku tidak terdefinisi). x.size()
karakter yang aman untuk dibaca, yaitu x[0]
melalui x[x.size() - 1]
&x[0]
f(const char* p, size_t n) { if (n == 0) return; ...apa pun... }
anda harus't call f(&x[0], x.size());
ketika x.kosong()
- hanya menggunakan f(x.data(), ...)
. x.data()
tetapi: const
x
ini menghasilkan non-const
char*
pointer; anda dapat menimpa string konten x.c_str()
const char*
ke ASCIIZ (NULL-terminated) representasi nilai (yaitu ['h', 'e', 'l', 'l', 'o', '\0']). x.data()
dan &x[0]
x.size()
+ 1 karakter yang aman untuk dibaca. string
fungsi anggota yang memodifikasi string
atau cadangan kapasitas yang lebih lanjut, setiap pointer nilai yang dikembalikan terlebih dahulu dengan salah satu metode di atas adalah valid. Anda dapat menggunakan metode-metode lagi untuk mendapatkan pointer lain. (Aturan yang sama seperti untuk iterator ke string). Lihat juga *Cara mendapatkan karakter pointer berlaku bahkan setelah
x` daun lingkup atau dimodifikasi lebih lanjut* di bawah ini....
Jadi, yang lebih baik ** untuk menggunakan? Dari C++11, gunakan .c_str()
untuk ASCIIZ data, dan .data()
untuk "biner" data (dijelaskan lebih lanjut di bawah).
Dalam C++03, gunakan .c_str()
kecuali yakin bahwa .data()
memadai, dan lebih memilih .data()
lebih dari &x[0]
sebagai it's aman untuk string kosong....
...mencoba untuk memahami program yang cukup untuk menggunakan data()
pada saat yang tepat, atau anda'mungkin akan membuat kesalahan-kesalahan lain...
ASCII NUL '\0' karakter yang dijamin oleh .c_str()
lebih banyak digunakan oleh fungsi-fungsi sebagai penjaga nilai yang menunjukkan akhir yang relevan dan aman-untuk-akses data. Hal ini berlaku untuk kedua C++-satunya fungsi seperti mengatakan fstream::fstream(const char* filename, ...)
dan berbagi-dengan-C fungsi seperti strchr()
, dan printf()
.
Diberikan C++03's .c_str()
's adalah tentang kembali buffer adalah super-set .data()
's, anda selalu dapat dengan aman menggunakan .c_str()
, tetapi orang-orang kadang-kadang don't karena:
.data()
berkomunikasi kepada programmer lain yang membaca kode sumber bahwa data tidak ASCIIZ (lebih tepatnya, kau're menggunakan string untuk menyimpan blok-blok data (yang kadang-kadang isn't bahkan benar-benar tekstual)), atau bahwa anda're diteruskan ke fungsi lain yang memperlakukan itu sebagai blok "biner" data. Ini bisa menjadi wawasan penting dalam memastikan bahwa programmer lain' perubahan kode terus menangani data dengan benar. string
implementasi akan perlu untuk melakukan beberapa tambahan alokasi memori dan/atau menyalin data dalam rangka mempersiapkan NUL dihentikan penyangga
Sebagai petunjuk lebih jauh, jika fungsi's parameter memerlukan (t
) char*
tapi don't bersikeras mendapatkan x.size()
, fungsi mungkin kebutuhan ASCIIZ input, jadi .c_str()
adalah pilihan yang baik (fungsi perlu tahu di mana teks yang berakhir entah bagaimana, jadi jika itu's tidak terpisah parameter itu hanya dapat konvensi seperti panjang-awalan atau sentinel atau tetap diharapkan suhu udara).
Cara mendapatkan karakter pointer berlaku bahkan setelah x
daun lingkup atau dimodifikasi lebih lanjut Anda'll perlu copy isi string
x
ke memori baru di luar daerah x
. Ini penyangga eksternal bisa berada di banyak tempat seperti yang lain string
atau karakter variabel array, itu mungkin atau mungkin tidak memiliki hidup yang berbeda dari x
karena sedang dalam ruang lingkup yang berbeda (misalnya namespace, global, statis, tumpukan, ruang memori, memori mapped file).
Untuk menyalin teks dari std::string x
menjadi karakter independen array:
// 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);
char*
atau const char*
yang dihasilkan dari string
Jadi, di atas anda've melihat bagaimana untuk mendapatkan (t
) char*
, dan bagaimana untuk membuat salinan dari teks independen asli string
, tapi apa yang bisa anda do dengan itu? Acak segelintir contoh-contoh...
string
's teks, seperti dalam printf("x '%s'", x.c_str());
x
's teks ke buffer ditentukan oleh fungsi's pemanggil (misalnya strncpy(callers_buffer, callers_buffer_size, x.c_str())
), atau volatile memori yang digunakan untuk perangkat I/O (misalnya untuk (const char* p = x.c_str(); *p; ++p) *p_device = *p;
) x
's teks untuk sebuah array karakter sudah mengandung beberapa ASCIIZ teks (misalnya strcat(other_buffer, x.c_str())
) - berhati-hati untuk tidak dikuasai buffer (dalam banyak situasi, anda mungkin perlu untuk menggunakan strncat
) const char*
atau char*
dari sebuah fungsi (mungkin untuk alasan historis - klien's menggunakan yang ada API - atau C kompatibilitas anda don't ingin kembali std::string
, tapi jangan ingin menyalin string
's data di suatu tempat untuk pemanggil) string
variabel mana yang pointer menunjuk telah meninggalkan lingkup std::string
implementasi (misalnya STLport dan compiler-pribumi) dapat menyampaikan data sebagai ASCIIZ untuk menghindari konflikGunakan .c_str()
metode const char *
.
Anda dapat menggunakan &mystring[0]
untuk mendapatkan char *
pointer, tetapi ada beberapa gotcha's: anda tidak't selalu mendapatkan nol string berakhir, dan anda tidak't dapat mengubah string's ukuran. Anda terutama harus berhati-hati untuk tidak menambahkan karakter melewati akhir dari string atau anda'll mendapatkan buffer overrun (dan kemungkinan kecelakaan).
Tidak ada jaminan bahwa semua karakter akan menjadi bagian yang sama bersebelahan penyangga sampai C++11, tetapi dalam prakteknya semua dikenal implementasi std::string
bekerja dengan cara itu pula, lihat Artinya "&s[0]" titik bersebelahan karakter di std::string?.
Perhatikan bahwa banyak string
fungsi anggota akan mengalokasikan buffer internal dan membatalkan pointer anda mungkin telah disimpan. Terbaik untuk menggunakan mereka segera dan kemudian buang.
C++17 (standar mendatang) perubahan sinopsis template basic_string
menambahkan non-const overload data()
:
grafik* data() noexcept;
Grafik const *
dari std::basic_string<Grafik>
std::string const cstr = { "..." };
char const * p = cstr.data(); // or .c_str()
Grafik *
dari std::basic_string<Grafik>
std::string str = { "..." };
char * p = str.data();
Grafik const *
dari std::basic_string<Grafik>
std::string str = { "..." };
str.c_str();
Grafik *
dari std::basic_string<Grafik>
Dari C++11 dan seterusnya, standar says:
- Char-benda seperti dalam
basic_string
objek akan disimpan secara menyatu. Artinya, untuk setiapbasic_string
objeks
, identitas&*(s.begin() + n) == &*s.begin() + n
akan tahan untuk semua nilain
seperti itu0 <= n < s.size()
.
const_reference operator[](size_type pos) const;
referensi operator[](size_type pos);
Kembali:
*(begin() + pos)
jikapos < size()
, atau referensi ke suatu objek dari jenisGrafik
dengan nilaiGrafik()
; direferensikan nilai tidak akan diubah.
const grafik* c_str() const noexcept;
const grafik* data() const noexcept;
Kembali: pointer p seperti yang
p + i == &operator[](i)
untuk setiapaku
dalam[0,size()]
.
Ada dapat dipisahkan cara yang mungkin untuk mendapatkan non-const karakter pointer.
std::string foo{"text"};
auto p = &*foo.begin();
Pro
Karena ...
'\0'
ini tidak dapat diubah-ubah / tidak harus selalu menjadi bagian dari non-const memori.std::vektor<Grafik>
std::string foo{"text"};
std::vector<char> fcv(foo.data(), foo.data()+foo.size()+1u);
auto p = fcv.data();
Pro
Karena ...
std::array<Grafik, N>
jika N
adalah waktu kompilasi konstan (dan cukup kecil)std::string foo{"text"};
std::array<char, 5u> fca;
std::copy(foo.data(), foo.data()+foo.size()+1u, fca.begin());
Pro
Karena ...
std::string foo{ "text" };
auto p = std::make_unique<char[]>(foo.size()+1u);
std::copy(foo.data(), foo.data() + foo.size() + 1u, &p[0]);
Pro
Karena ...
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
Con
Saya bekerja dengan API dengan banyak fungsi bisa sebagai masukan char*
.
Saya telah menciptakan sebuah kelas kecil untuk menghadapi masalah seperti ini, saya telah menerapkan RAII idiom.
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_; }
};
Dan anda dapat menggunakannya sebagai:
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 disebut kelas DeepString
karena itu adalah menciptakan mendalam dan unik menyalin (DeepString
tidak copyable) yang ada string.
Hanya melihat ini :
string str1("stackoverflow");
const char * str2 = str1.c_str();
Namun , perhatikan bahwa ini akan kembali const char *
.Untuk char *
, gunakan strcpy
untuk menyalin ke lain char
array.