std :: string to char *

335

Saya ingin mengonversi std :: string menjadi char * atau char [] .

std::string str = "string";
char* chr = str;

Hasil dalam: "kesalahan: tidak dapat mengkonversi 'std :: string' ke 'char' ..." .

Metode apa yang tersedia untuk melakukan ini?


sumber

Jawaban:

672

Itu tidak akan secara otomatis mengkonversi (terima kasih Tuhan). Anda harus menggunakan metode ini c_str()untuk mendapatkan versi string C.

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

Perhatikan bahwa ia mengembalikan a const char *; Anda tidak diizinkan mengubah string C-style yang dikembalikan oleh c_str(). Jika Anda ingin memprosesnya, Anda harus menyalinnya terlebih dahulu:

std::string str = "string";
char *cstr = new char[str.length() + 1];
strcpy(cstr, str.c_str());
// do stuff
delete [] cstr;

Atau di C ++ modern:

std::vector<char> cstr(str.c_str(), str.c_str() + str.size() + 1);
orlp
sumber
4
@ Gerrek SB: Itu adalah contoh, akan menggunakan smart pointer dalam kode nyata, atau lebih mungkin menghindari c_strkegilaan ini sepenuhnya.
orlp
14
Jawabannya besar, tidak elegan, non-lokal, menggunakan array mentah, dan membutuhkan perhatian terhadap keamanan pengecualian. vectordiciptakan tepat sebagai pembungkus untuk array dinamis, jadi tidak menggunakannya sepertinya peluang yang terlewatkan, dan yang melanggar semangat C ++ paling buruk.
Kerrek SB
21
Pertama-tama, ya jawabannya besar. Pertama saya menjelaskan kesalahan OP (berpikir bahwa std::stringakan secara otomatis mengkonversi) dan kemudian saya menjelaskan apa yang harus dia gunakan, dengan contoh kode pendek. Berpikir ke depan Saya juga menjelaskan beberapa efek samping dari penggunaan fungsi ini, di antaranya adalah Anda tidak boleh mengedit string yang dikembalikan oleh c_str(). Anda keliru melihat contoh singkat saya sebagai kode pemecahan masalah yang nyata, padahal bukan.
orlp
8
Saya menurunkan jawaban. Jawaban ini memang tidak berguna dan fakta bahwa itu diterima sangat disayangkan. Jawaban ini sepenuhnya mengabaikan praktik pemrograman C ++ yang baik dan keselamatan pengecualian dan ada solusi yang jauh lebih unggul, beberapa di antaranya diberikan dalam jawaban lain untuk pertanyaan ini (misalnya jawaban yang diberikan oleh ildjarn yang menggunakan std::vector<char>).
James McNellis
114
@ james-mcnellis, saya memilih jawaban ini sebagai jawaban yang benar karena menjawab PERSIS apa yang saya minta ... Tidak lebih, tidak kurang. Saya tidak meminta apa yang menurut Anda harus saya lakukan, saya tidak meminta solusi berbeda untuk apa yang Anda pikir saya lakukan, saya tidak meminta praktik yang baik. Anda tidak tahu apa yang saya kerjakan, di mana kode saya akan diimplementasikan dan dalam kondisi apa. Beberapa orang harus belajar membaca, memahami pertanyaan dan menjawab apa yang sebenarnya ditanyakan. Tidak perlu pamer di sini.
151

Lebih detail di sini , dan di sini tetapi Anda dapat menggunakan

string str = "some string" ;
char *cstr = &str[0];
bobobobo
sumber
15
FWIW, dalam buku saya, ini adalah satu-satunya jawaban yang benar untuk pertanyaan yang sebenarnya ditanyakan. String std :: secara inheren bisa berubah: orang-orang yang membuatnya terdengar seperti memodifikasi isi string entah bagaimana pekerjaan iblis tampaknya melewatkan fakta ini.
Jay Freeman -saurik-
2
ya, ini jawaban yang benar. itu konyol bahwa, mengingat frekuensi penggunaan, tidak ada metode standar untuk melakukan ini, seperti pembuat kunci msoft.
Erik Aronesty
1
Saya mengubah 0 menjadi 0u. Karena beberapa kompiler / perpustakaan akan (percaya atau tidak) mengeluh tentang ambiguitas ketika peringatan dihidupkan untuk konstruksi & str [0]
Erik Aronesty
Saya ragu ketika str dihapus, char cstr dibuat nol. Jadi saya kira di sini hanya pointer dari string yang ditugaskan ke pointer char. Jadi konversi string menjadi char tidak lengkap secara harfiah. String hanya menunjuk ke char * tetapi nilainya tidak dikonversi. Apakah saya benar???
Samitha Chathuranga
5
Perhatikan bahwa ini hanya C ++ 11. Versi sebelumnya mungkin tidak memiliki penyimpanan berkelanjutan atau tidak memiliki null penghentian
Flamefire
39

Jika saya memerlukan salinan mentah yang dapat diubah dari isi string c ++, maka saya akan melakukan ini:

std::string str = "string";
char* chr = strdup(str.c_str());

dan kemudian:

free(chr); 

Jadi mengapa saya tidak bermain-main dengan std :: vector atau baru [] seperti orang lain? Karena ketika saya membutuhkan string char * raw C-style yang dapat diubah, maka karena saya ingin memanggil kode C yang mengubah string dan kode C mengalokasikan barang dengan bebas () dan mengalokasikan dengan malloc () (strdup menggunakan malloc) . Jadi jika saya lulus string baku saya untuk beberapa fungsi X ditulis dalam C itu mungkin memiliki kendala pada argumen itu yang telah untuk dialokasikan di heap (misalnya jika fungsi mungkin ingin menelepon realloc pada parameter). Tetapi sangat tidak mungkin bahwa itu akan mengharapkan argumen dialokasikan dengan (beberapa pengguna-didefinisikan ulang) baru []!

Mainframe Nordik
sumber
Anda harus menjelaskan dari mana asalnya strdup.
LF
22

(Jawaban ini hanya berlaku untuk C ++ 98.)

Tolong, jangan gunakan mentah char*.

std::string str = "string";
std::vector<char> chars(str.c_str(), str.c_str() + str.size() + 1u);
// use &chars[0] as a char*
ildjarn
sumber
1
Sebenarnya saya hanya butuh sesuatu seperti ini sebelumnya hari ini. Saya bertanya-tanya, apakah boleh mengatakan vector<char>(str.c_str(), str.c_str() + str.size() + 1), tanpa menetapkan pointer char untuk sementara?
Kerrek SB
1
@ Gerrek: Ya, nilai balik std::basic_string<>::c_str()valid hingga stringdiubah atau dimusnahkan. Ini juga menyiratkan bahwa ia mengembalikan nilai yang sama pada panggilan berikutnya selama stringtidak diubah.
ildjarn
2
@friendzis: Tidak ada kecepatan atau overhead ruang menggunakan vectorcara ini. Dan jika seseorang menulis kode pengecualian-aman tanpa mekanisme RAII (yaitu, menggunakan pointer mentah), kompleksitas kode akan jauh lebih tinggi daripada ini satu-liner sederhana.
ildjarn
7
Itu adalah mitos yang vectormemiliki overhead dan kompleksitas yang sangat besar. Jika kebutuhan Anda adalah bahwa Anda memiliki array char yang bisa berubah , maka sebenarnya vektor karakter adalah pembungkus C ++ yang ideal. Jika kebutuhan Anda sebenarnya hanya memanggil pointer const-char, maka cukup gunakan c_str()dan Anda selesai.
Kerrek SB
3
@ildjarn: Sebenarnya, pada dasarnya itu .
Lightness Races di Orbit
14
  • Jika Anda hanya ingin string gaya-C yang mewakili konten yang sama:

    char const* ca = str.c_str();
  • Jika Anda ingin string gaya-C dengan konten baru , satu cara (mengingat Anda tidak tahu ukuran string pada waktu kompilasi) adalah alokasi dinamis:

    char* ca = new char[str.size()+1];
    std::copy(str.begin(), str.end(), ca);
    ca[str.size()] = '\0';

    Jangan lupa delete[]nanti.

  • Jika Anda menginginkan array yang dialokasikan secara statis, maka array dengan panjang terbatas:

    size_t const MAX = 80; // maximum number of chars
    char ca[MAX] = {};
    std::copy(str.begin(), (str.size() >= MAX ? str.begin() + MAX : str.end()), ca);

std::stringtidak secara implisit mengkonversi ke jenis ini untuk alasan sederhana yang perlu melakukan ini biasanya bau desain. Pastikan Anda benar - benar membutuhkannya.

Jika Anda benar - benar membutuhkan char*, cara terbaik mungkin:

vector<char> v(str.begin(), str.end());
char* ca = &v[0]; // pointer to start of vector
Lightness Races di Orbit
sumber
1
Mengapa &str.front(), &str.back()(yang tidak ada dalam C ++ 03) bukannya yang lebih umum str.begin()dan str.end()?
Armen Tsirunyan
1
bagaimana dengan str.begin(), atau bahkan std::begin(str), seperti iterator? Saya tidak percaya stringmemiliki kewajiban untuk berada di memori yang berdekatan seperti vector, atau bukan?
xtofl
1
@xtofl: Saya sudah mengedit yang masuk. Dan ya, pada C ++ 11 ada kewajiban; ini tersirat dalam C ++ 03.
Lightness Races in Orbit
@xtofl: Tidak dalam C ++ 03. Dalam C ++ 11 kami memiliki jaminan itu, bersama dengan fungsi depan () dan belakang (), yang disalahgunakan dalam jawaban asli
Armen Tsirunyan
1
@ Tomalak: Mereka disalahgunakan dalam kebutuhan Anda &back() + 1, bukan&back()
Armen Tsirunyan
12

Ini akan lebih baik sebagai komentar pada jawaban bobobobo, tetapi saya tidak memiliki perwakilan untuk itu. Ini mencapai hal yang sama tetapi dengan praktik yang lebih baik.

Meskipun jawaban lain yang berguna, jika Anda merasa perlu untuk mengkonversi std::stringke char*eksplisit tanpa const, const_castadalah teman Anda.

std::string str = "string";
char* chr = const_cast<char*>(str.c_str());

Perhatikan bahwa ini tidak akan memberi Anda salinan data; itu akan memberi Anda pointer ke string. Jadi, jika Anda memodifikasi elemen chr, Anda akan memodifikasi str.

tidak berambut
sumber
6

Dengan asumsi Anda hanya perlu string gaya-C untuk lulus sebagai input:

std::string str = "string";
const char* chr = str.c_str();
Mark B
sumber
4

Agar benar-benar bertele-tele, Anda tidak dapat "mengubah string std :: menjadi tipe data char * atau char []."

Seperti yang ditunjukkan oleh jawaban lain, Anda dapat menyalin konten std :: string ke array char, atau membuat const char * ke konten std :: string sehingga Anda dapat mengaksesnya dalam "gaya C" .

Jika Anda mencoba mengubah konten std :: string, tipe std :: string memiliki semua metode untuk melakukan apa pun yang mungkin perlu Anda lakukan untuk itu.

Jika Anda mencoba meneruskannya ke beberapa fungsi yang mengambil char *, ada std :: string :: c_str ().

Rob K
sumber
4

Ini adalah satu lagi versi yang lebih kuat dari Protocol Buffer

char* string_as_array(string* str)
{
    return str->empty() ? NULL : &*str->begin();
}

// test codes
std::string mystr("you are here");
char* pstr = string_as_array(&mystr);
cout << pstr << endl; // you are here
zangw
sumber
+1 untuk memeriksa apakah string kosong. Saya juga akan menambahkan cek untuk memastikan bahwa string tidak diakhiri: if (str[str.length()-1] != 0) str.push_back(0)
GaspardP
4

Konversi dalam gaya OOP

converter.hpp

class StringConverter {
    public: static char * strToChar(std::string str);
};

converter.cpp

char * StringConverter::strToChar(std::string str)
{
    return (char*)str.c_str();
}

pemakaian

StringConverter::strToChar("converted string")
Patryk Merchelski
sumber
Saya suka bagaimana para pemain untuk char * menghilangkan const dari output c_str, saya pikir alasan c_str mengembalikan const char * adalah untuk menghilangkan masalah akses memori potensial, dengan menyediakan versi read only dari hal itu. OP ingin memiliki char *, tapi saya pikir dia mungkin lebih baik dilayani oleh const char * output dari c_str sebagai gantinya, karena itu lebih aman, dan fungsi yang mengambil char * biasanya mengambil const char * juga (dengan asumsi fungsi tidak lakukan apa saja seperti mengubah input mereka, yang secara umum tidak seharusnya).
Felipe Valdes
3

Demi kelengkapan, jangan lupa std::string::copy().

std::string str = "string";
const size_t MAX = 80;
char chrs[MAX];

str.copy(chrs, MAX);

std::string::copy()tidak NUL berakhir. Jika Anda perlu memastikan terminator NUL untuk digunakan dalam fungsi string C:

std::string str = "string";
const size_t MAX = 80;
char chrs[MAX];

memset(chrs, '\0', MAX);
str.copy(chrs, MAX-1);
Jeffery Thomas
sumber
3

Anda bisa membuatnya menggunakan iterator.

std::string str = "string";
std::string::iterator p=str.begin();
char* chr = &(*p);

Semoga berhasil.

TS.PARK
sumber
3

Versi aman dari jawaban orlp char * menggunakan unique_ptr:

std::string str = "string";
auto cstr = std::make_unique<char[]>(str.length() + 1);
strcpy(cstr.get(), str.c_str());
Enhex
sumber
3

Untuk mendapatkan a const char * dari std::stringpenggunaan c_str()fungsi anggota:

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

Untuk mendapatkan non-const char * dari std::stringAnda dapat menggunakan data()fungsi anggota yang mengembalikan pointer non-const sejak C ++ 17:

std::string str = "string";
char* chr = str.data();

Untuk versi bahasa yang lebih lama, Anda bisa menggunakan konstruksi rentang untuk menyalin string ke dalam vektor dari mana pointer non-const dapat diperoleh:

std::string str = "string";
std::vector<char> str_copy(str.c_str(), str.c_str() + str.size() + 1);
char* chr = str_copy.data();

Tetapi berhati-hatilah karena ini tidak akan membiarkan Anda memodifikasi string yang terkandung str, hanya data salinan yang dapat diubah dengan cara ini. Perhatikan bahwa ini sangat penting dalam versi bahasa yang lebih lama untuk digunakan di c_str()sini karena pada saat std::stringitu tidak dijamin akan dibatalkan nol sampai c_str()dipanggil.

François Andrieux
sumber
2
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());
cegprakash
sumber
2

Atau, Anda dapat menggunakan vektor untuk mendapatkan karakter * yang dapat ditulisi seperti yang ditunjukkan di bawah ini;

//this handles memory manipulations and is more convenient
string str;
vector <char> writable (str.begin (), str.end) ;
writable .push_back ('\0'); 
char* cstring = &writable[0] //or &*writable.begin () 

//Goodluck  

sumber
Ini akan mengalokasikan memori baru untuk vektor dan kemudian menyalin setiap karakter. std :: string sudah menjadi wadah, Anda mungkin juga push_back (0) ke string Anda dan lakukan & str [0]
GaspardP
1

Ini juga akan berfungsi

std::string s;
std::cout<<"Enter the String";
std::getline(std::cin, s);
char *a=new char[s.size()+1];
a[s.size()]=0;
memcpy(a,s.c_str(),s.size());
std::cout<<a;  
Genocide_Hoax
sumber