Pertanyaan Bagaimana cara mengubah std :: string ke const char * atau char *?


Bagaimana saya bisa mengonversi std::string ke a char* atau a const char*?


777
2017-12-07 19:30


asal


Jawaban:


Jika Anda hanya ingin lulus std::string ke fungsi yang dibutuhkan const char* Kamu dapat memakai

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

Jika Anda ingin mendapatkan salinan yang dapat ditulis, seperti char *, Anda dapat melakukannya 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 hal di atas tidak terkecuali aman. Jika ada sesuatu di antara new panggilan dan delete panggil panggilan, Anda akan membocorkan memori, karena tidak ada yang akan menelepon delete untuk Anda secara otomatis. Ada dua cara cepat 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(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

Ini adalah cara standar (tidak memerlukan pustaka eksternal). Kau gunakan 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()

932
2017-12-07 19:31



Diberikan katakan ...

std::string x = "hello";

 Mendapatkan `char *` atau `const char *` dari `string`

Cara mendapatkan penunjuk karakter itu berlaku sementara x tetap dalam lingkup dan tidak dimodifikasi lebih lanjut

C ++ 11 menyederhanakan berbagai hal; berikut ini semua memberikan akses ke buffer string internal yang sama:

const char* p_c_str = x.c_str();
const char* p_data  = x.data();
const char* p_x0    = &x[0];

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

Semua pointer di atas akan menahan nilai yang sama - alamat karakter pertama dalam 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 (misalnya std::string("this\0that", 9) akan memiliki buffer holding "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 tidakconst penunjuk dari &x[0]:

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(); string's diperbolehkan mengandung sejumlah NUL - mereka tidak diberi perlakuan khusus oleh std::string (Sama dengan C ++ 03).

Di C ++ 03, semuanya jauh lebih rumit (perbedaan utama disorot):

  • x.data()

    • kembali const char* ke buffer internal string yang tidak diperlukan oleh Standar untuk diakhiri dengan NUL (mungkin saja ['h', 'e', 'l', 'l', 'o'] diikuti oleh nilai-nilai yang tidak diinisialisasi atau sampah, dengan akses yang tidak disengaja perilaku tidak terdefinisi).
      • x.size() karakter aman untuk dibaca, mis. x[0] melalui x[x.size() - 1]
      • untuk string kosong, Anda dijamin beberapa pointer non-NULL yang mana 0 dapat ditambahkan dengan aman (hore!), tetapi Anda tidak perlu mengalihkan pointer itu.
  • &x[0]

    • untuk string kosong ini memiliki perilaku yang tidak terdefinisi (21.3.4)
      • misalnya 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() - Cukup gunakan f(x.data(), ...).
    • jika tidak, sesuai x.data() tapi:
      • untuk bukanconst  x ini menghasilkan non-const  char* penunjuk; Anda dapat menimpa konten string
  • x.c_str()

    • kembali const char* ke ASCIIZ (NUL-diakhiri) representasi nilai (yaitu ['h', 'e', ​​'l', 'l', 'o', '\ 0']).
    • meskipun beberapa jika ada implementasi yang memilih untuk melakukannya, Standar C ++ 03 diberi kata untuk memungkinkan implementasi string kebebasan untuk membuat a buffer NUL-dihentikan yang berbeda  dengan cepat, dari buffer yang berpotensi non-NUL dihentikan "terkena" oleh x.data() dan &x[0]
    • x.size() + 1 karakter aman dibaca.
    • dijamin aman bahkan untuk string kosong (['\ 0']).

Konsekuensi mengakses indeks hukum luar

Apapun cara Anda mendapatkan pointer, Anda tidak harus mengakses memori lebih jauh dari pointer daripada karakter yang dijamin hadir dalam uraian di atas. Upaya untuk melakukannya perilaku tidak terdefinisi, dengan kemungkinan yang sangat nyata dari aplikasi crash dan hasil sampah bahkan untuk membaca, dan data tambahan grosir, tumpukan korupsi dan / atau kerentanan keamanan untuk menulis.

Kapan pointer tersebut menjadi batal?

Jika Anda memanggil beberapa string fungsi anggota yang memodifikasi string atau cadangan kapasitas lebih lanjut, setiap nilai penunjuk yang dikembalikan sebelumnya oleh salah satu metode di atas adalah batal. Anda dapat menggunakan kembali metode tersebut untuk mendapatkan penunjuk lain. (Aturannya sama seperti untuk iterator strings).

Lihat juga Cara mendapatkan penunjuk karakter valid bahkan setelah x daun ruang lingkup atau dimodifikasi lebih lanjut di bawah....

Jadi, itulah lebih baik menggunakan?

Dari C ++ 11, gunakan .c_str() untuk data ASCIIZ, dan .data() untuk data "biner" (dijelaskan lebih lanjut di bawah).

Dalam C ++ 03, gunakan .c_str() kecuali yakin itu .data() memadai, dan lebih suka .data() lebih &x[0] karena aman untuk string kosong ....

... cobalah untuk memahami program yang cukup untuk digunakan data() bila perlu, atau Anda mungkin akan membuat kesalahan lain ...

Karakter ASCII NUL '\ 0' dijamin oleh .c_str() digunakan oleh banyak fungsi sebagai nilai sentinel yang menunjukkan akhir dari data yang relevan dan aman untuk diakses. Ini berlaku untuk fungsi C ++ - hanya seperti mengucapkan fstream::fstream(const char* filename, ...) dan fungsi shared-with-C seperti strchr(), dan printf().

Diberikan C ++ 03's .c_str()Jaminan tentang buffer yang dikembalikan adalah seperangkat super .data()ini, Anda selalu dapat menggunakan dengan aman .c_str(), tetapi terkadang orang tidak melakukannya karena:

  • menggunakan .data() berkomunikasi dengan programmer lain yang membaca kode sumber bahwa datanya bukan ASCIIZ (lebih tepatnya, Anda menggunakan string untuk menyimpan blok data (yang kadang-kadang bahkan tidak benar-benar tekstual)), atau bahwa Anda meneruskannya ke yang lain fungsi yang memperlakukannya sebagai blok data "biner". Ini dapat menjadi wawasan penting dalam memastikan bahwa perubahan kode programmer lain terus menangani data dengan benar.
  • C + + 03 saja: ada sedikit kemungkinan bahwa Anda string implementasi akan perlu melakukan beberapa alokasi memori tambahan dan / atau penyalinan data untuk menyiapkan buffer diakhiri NUL

Sebagai petunjuk lebih lanjut, jika parameter fungsi memerlukan (const) char* tapi jangan memaksakan untuk mendapatkannya x.size(), fungsi itu mungkin membutuhkan input ASCIIZ, jadi .c_str() adalah pilihan yang baik (fungsi perlu tahu di mana teks berakhir entah bagaimana, jadi jika itu bukan parameter yang terpisah itu hanya bisa menjadi konvensi seperti awalan panjang atau sentinel atau beberapa panjang yang diharapkan tetap).

Cara mendapatkan penunjuk karakter valid bahkan setelah x daun ruang lingkup atau dimodifikasi lebih lanjut

Anda harus melakukannya salinan isi dari string  x ke area memori baru di luar x. Penyangga eksternal ini bisa berada di banyak tempat seperti yang lain string atau variabel karakter array, mungkin atau mungkin tidak memiliki masa hidup yang berbeda x karena berada dalam cakupan yang berbeda (misalnya namespace, global, statis, heap, memori bersama, file yang dipetakan memori).

Untuk menyalin teks dari std::string x ke dalam susunan 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) 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);

Alasan lain menginginkan sebuah char* atau const char* dihasilkan dari string

Jadi, di atas Anda telah melihat cara mendapatkan (const) char*, dan bagaimana membuat salinan teks yang independen dari aslinya string, tetapi apa yang bisa Anda lakukan melakukan dengan itu? Contoh-contoh acak ...

  • memberi "C" akses kode ke C ++ stringteks, seperti pada printf("x is '%s'", x.c_str());
  • salinan xteks ke buffer yang ditentukan oleh pemanggil fungsi Anda (mis. strncpy(callers_buffer, callers_buffer_size, x.c_str())), atau memori volatile yang digunakan untuk perangkat I / O (mis. for (const char* p = x.c_str(); *p; ++p) *p_device = *p;)
  • menambahkan xteks ke larik karakter sudah berisi beberapa teks ASCIIZ (mis. strcat(other_buffer, x.c_str())) - hati-hati untuk tidak membanjiri buffer (dalam banyak situasi yang mungkin perlu Anda gunakan strncat)
  • kembalikan a const char* atau char* dari fungsi (mungkin karena alasan historis - klien menggunakan API Anda yang ada - atau untuk kompatibilitas C Anda tidak ingin mengembalikan a std::string, tetapi ingin menyalin Anda stringdata di suatu tempat untuk pemanggil)
    • hati-hati untuk tidak mengembalikan pointer yang mungkin dereferenced oleh penelepon setelah lokal string variabel yang menunjuk pointer yang memiliki ruang lingkup kiri
    • beberapa proyek dengan objek bersama yang dikompilasi / ditautkan untuk berbeda std::string implementasi (mis. STLport dan compiler-native) dapat meneruskan data sebagai ASCIIZ untuk menghindari konflik

173
2018-01-12 15:53



Menggunakan .c_str() metode untuk const char *.

Kamu dapat memakai &mystring[0] untuk mendapatkan char * pointer, tetapi ada beberapa gotcha: Anda tidak akan selalu mendapatkan string yang diakhiri nol, dan Anda tidak akan dapat mengubah ukuran string. Anda terutama harus berhati-hati untuk tidak menambahkan karakter melewati ujung string atau Anda akan mendapatkan buffer overrun (dan kemungkinan crash).

Tidak ada jaminan bahwa semua karakter akan menjadi bagian dari buffer bersebelahan yang sama sampai C ++ 11, tetapi dalam prakteknya semua implementasi yang dikenal dari std::string bekerja dengan cara itu; Lihat Apakah "& s [0]" mengarah ke karakter yang bersebelahan dalam std :: string?.

Perhatikan bahwa banyak string fungsi anggota akan mengalokasikan kembali buffer internal dan membatalkan pointer apa pun yang mungkin telah Anda simpan. Lebih baik gunakan dengan segera dan kemudian buang.


31
2018-03-29 13:32



C ++ 17

C ++ 17 (standar yang akan datang) mengubah sinopsis dari template basic_string menambahkan overload non const dari data():

charT* data() noexcept;

Pengembalian: Sebuah penunjuk p sedemikian hingga p + i == & operator untuk setiap i dalam [0, ukuran ()].


CharT const * dari std::basic_string<CharT>

std::string const cstr = { "..." };
char const * 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:

  1. Objek mirip-char di dalam basic_string objek harus disimpan secara berdekatan. Yaitu, untuk apa saja basic_string obyek s, identitas &*(s.begin() + n) == &*s.begin() + n akan berlaku untuk semua nilai nseperti yang 0 <= n < s.size().

  1. const_reference operator[](size_type pos) const; 
      reference operator[](size_type pos); 

    Pengembalian: *(begin() + pos) jika pos < size(), jika tidak referensi ke objek tipe CharT dengan nilai CharT(); nilai yang direferensikan tidak akan dimodifikasi.


  1. const charT* c_str() const noexcept;
    const charT* data() const noexcept;

    Pengembalian: Sebuah penunjuk p seperti itu p + i == &operator[](i) untuk setiap i di [0,size()].

Ada banyak kemungkinan cara untuk mendapatkan penunjuk karakter non const.

1. Gunakan penyimpanan berdekatan C ++ 11

std::string foo{"text"};
auto p = &*foo.begin();

Pro

  • Sederhana dan singkat
  • Cepat (hanya metode tanpa salinan yang terlibat)

Cons

  • Terakhir '\0' tidak diubah / belum tentu bagian dari memori non-const.

2. Gunakan std::vector<CharT>

std::string foo{"text"};
std::vector<char> fcv(foo.data(), foo.data()+foo.size()+1u);
auto p = fcv.data();

Pro

  • Sederhana
  • Penanganan memori otomatis
  • Dinamis

Cons

  • Membutuhkan copy string

3. Gunakan std::array<CharT, 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

  • Sederhana
  • Penanganan memori stack

Cons

  • Statis
  • Membutuhkan copy string

4. Alokasi memori baku dengan penghapusan penyimpanan otomatis

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

  • Jejak memori kecil
  • Penghapusan otomatis
  • Sederhana

Cons

  • Membutuhkan copy string
  • Statis (penggunaan dinamis membutuhkan lebih banyak kode)
  • Fitur kurang dari vektor atau larik

5. Alokasi memori baku dengan penanganan manual

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

  • Kontrol maksimum '

Menipu

  • Membutuhkan copy string
  • Kewajiban maksimum / kerentanan untuk kesalahan
  • Kompleks

18
2017-07-12 12:06



Saya bekerja dengan API dengan banyak fungsi sebagai input a char*.

Saya telah membuat kelas kecil untuk menghadapi masalah semacam ini, saya telah menerapkan idiom RAII.

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 sudah menelepon kelas DeepString karena itu menciptakan salinan yang dalam dan unik (yang DeepString tidak dapat dikirim) dari string yang ada.


9
2018-05-12 08:18



char* result = strcpy((char*)malloc(str.length()+1), str.c_str());

7
2018-02-17 16:45



Lihat saja ini:

string str1("stackoverflow");
const char * str2 = str1.c_str();

Namun, perhatikan bahwa ini akan mengembalikan a const char *.Untuk sebuah char *, gunakan strcpy untuk menyalinnya ke yang lain char larik.


7



Coba ini

std::string s(reinterpret_cast<const char *>(Data), Size);

-4