std :: karakter dizisi *


335

Bir std :: string bir char * veya char [] veri türüne dönüştürmek istiyorum .

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

Sonuçlar: “hata: 'std :: string' öğesini 'char' haline dönüştüremiyor ...” .

Bunu yapmak için hangi yöntemler var?

c++  string  char 

Yanıtlar:


672

Otomatik olarak dönüştürülmez (şükürler olsun). c_str()C dize sürümünü almak için yöntemi kullanmanız gerekir.

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

Bir const char *; tarafından döndürülen C stili dizeyi değiştirmenize izin verilmiyor c_str(). İşlemek istiyorsanız önce kopyalamanız gerekir:

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

Veya modern C ++ ile:

std::vector<char> cstr(str.c_str(), str.c_str() + str.size() + 1);

4
@Kerrek SB: Bir örnekti, gerçek kodda akıllı bir işaretçi kullanırdı veya bu c_strdelilikten tamamen kaçınırdı .
orlp

14
Cevap hantal, beceriksiz, yerel değil, ham diziler kullanıyor ve istisna güvenliğe dikkat gerektiriyor. vectordinamik diziler için bir sargı olarak icat edildi, bu yüzden kullanmamak en iyi ihtimalle kaçırılmış bir fırsat gibi görünüyor ve en kötü ihtimalle C ++ ruhunu ihlal ediyor.
Kerrek SB

21
Her şeyden önce, evet cevap hantal. Önce OP'nin hatasını ( std::stringotomatik olarak dönüştüğünü düşünerek ) ve sonra ne kullanması gerektiğini kısa kod örneği ile açıklarım. İleriye dönük olarak, bu işlevin kullanımının bazı yan etkilerini de açıklarım, bunlardan biri döndürülen dizeyi düzenleyemeyeceğinizdir c_str(). Yanlışlıkla kısa örneklerimi gerçek problem çözme kodu olarak görüyorsunuz.
orlp

8
Cevabı düşürdüm. Bu cevap gerçekten yararlı değildir ve kabul edilmesi gerçeği en talihsizdir. Bu cevap iyi C ++ programlama uygulamalarını ve istisna güvenliği tamamen göz ardı eder ve bazıları bu sorunun diğer cevaplarında verilen çok daha üstün çözümler vardır (örneğin, ildjarn'ın kullandığı cevap std::vector<char>).
James McNellis

114
@ james-mcnellis, bu cevabı doğru olarak seçtim çünkü tam olarak ne istediğimi yanıtladı ... Daha fazla, daha az değil. Yapmam gerektiğini düşündüğünüzü sormadım, yaptığımı düşündüğün için farklı bir çözüm istemedim, iyi uygulamalar istemedim. Ne içinde çalıştığım, kodumun nerede ve hangi koşullar altında uygulanacağı hakkında hiçbir fikriniz yok. Bazıları soruları okumayı, anlamayı ve sorulan sorulara cevap vermeyi öğrenmelidir. Burada göstermeye gerek yok.

150

Burada ve burada daha fazla ayrıntı ama kullanabilirsiniz

string str = "some string" ;
char *cstr = &str[0];

15
FWIW, kitabımda, aslında sorulan soruya verilen tek doğru cevap bu. Bir std :: string doğal olarak değişkendir: dizenin içeriğini değiştirmek gibi ses çıkartan insanlar şeytanın işi bir şekilde bu gerçeği kaçırıyor gibi görünüyor.
Jay Freeman -saurik-

2
evet, bu doğru cevap. kullanım sıklığı göz önüne alındığında, bunu yapmak için standart bir yöntem yoktur, msoft'un lockbuffer'ı gibi.
Erik Aronesty

1
0'ı 0u olarak değiştirdim. Çünkü bazı derleyiciler / kütüphaneler & str [0] yapısı için uyarılar tamamen açıldığında bazı belirsizlikler hakkında (ister inanın ister inanmayın) şikayet
edecekler

Str silindiğinde şüphe, char cstr boş yapılır. Bu yüzden karakter dizisine yalnızca dizenin bir işaretçisi atanır sanırım. Yani dizenin char'a dönüşümü tam anlamıyla tamamlanmış değil. Dize yalnızca char * 'a işaret edilir, ancak değeri dönüştürülmez. Doğrumuyum???
Samitha Chathuranga

5
Bunun yalnızca C ++ 11 olduğunu unutmayın. Önceki sürümlerde sürekli depolama olmayabilir veya sonlandırma null
değerinde

39

Bir c ++ 's dize içeriğinin değiştirilebilir bir ham kopya gerekir, o zaman bunu yapmak:

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

ve sonra:

free(chr); 

Öyleyse neden başka biri gibi std :: vector veya new [] ile uğraşmıyorum? Çünkü ben bir değişken C tarzı ham kömürü gerektiğinde * dize, o zaman dize değiştirir ve C kodu malloc () (strdup kullanımlar malloc) olan serbest () ve ayırır ile malzeme kaldırır C kodu aramak istiyorum çünkü . Bazı fonksiyon X'e benim ham dize geçirirseniz Yani C ile yazılmış bu olabilir o kadar yığın tahsis ettiğini 's argüman üzerinde bir sınırlama var (örneğin fonksiyon parametreye realloc aramak istersin ise). Ancak (bazı kullanıcı tarafından yeniden tanımlanmış) yeni [] ile ayrılmış bir argüman beklemesi pek olası değildir!


Nereden strdupgeldiğini açıklamalısın .
LF

22

(Bu yanıt yalnızca C ++ 98 için geçerlidir.)

Lütfen, çiğ kullanmayın char*.

std::string str = "string";
std::vector<char> chars(str.c_str(), str.c_str() + str.size() + 1u);
// use &chars[0] as a char*

1
Aslında bugün böyle bir şeye ihtiyacım vardı. Merak ediyordum, vector<char>(str.c_str(), str.c_str() + str.size() + 1)char işaretçisini geçici olarak atamadan söylemek doğru mudur?
Kerrek SB

1
@Kerrek: Evet, öğesinin dönüş değeri değiştirilene veya yok std::basic_string<>::c_str()edilene kadar geçerlidir string. Bu ayrıca, stringdeğiştirilmediği sürece sonraki aramalarda aynı değeri döndürdüğü anlamına gelir .
ildjarn

2
@friendzis: vectorBu şekilde kullanılan bir hız veya boşluk ek yükü yoktur . Ve eğer bir RAII mekanizması olmadan istisna-güvenli kod yazacak olsaydı (yani ham işaretçiler kullanarak), kod karmaşıklığı bu basit tek-kattan çok daha yüksek olurdu.
ildjarn

7
vectorBüyük miktarda ek yük ve karmaşıklığa sahip bir efsane . İhtiyacınız değişebilir bir char dizisine sahipseniz, aslında bir char vektörü hemen hemen ideal C ++ sarıcıdır. Gereksiniminiz aslında bir const-char işaretçisi gerektiriyorsa, sadece kullanın c_str()ve işiniz bitti.
Kerrek SB


14
  • Yalnızca aynı içeriği temsil eden bir C stili dize istiyorsanız:

    char const* ca = str.c_str();
  • Yeni içeriğe sahip bir C stili dize istiyorsanız, derleme zamanında dize boyutunu bilmediğinizden biri dinamik ayırmadır:

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

    Daha delete[]sonra unutmayın .

  • Bunun yerine statik olarak ayrılmış, sınırlı uzunlukta bir dizi istiyorsanız:

    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::stringbunu yapmanın genellikle bir tasarım kokusu olmasının basit bir nedeni için örtük olarak bu türlere dönüşmez. Gerçekten emin ol ihtiyacınız .

Kesinlikle bir ihtiyacınız varsa char*, en iyi yol muhtemelen:

vector<char> v(str.begin(), str.end());
char* ca = &v[0]; // pointer to start of vector

1
Neden &str.front(), &str.back()(C ++ 03'te mevcut değil) yerine daha yaygın str.begin()ve str.end()?
Armen Tsirunyan

1
Ne yaklaşık str.begin(), hatta std::begin(str), yineleyici benzeri? Sanırım stringbitişik hafızada olmak gibi bir yükümlülüğüm vectoryok mu, öyle mi?
xtofl

1
@xtofl: Bunları zaten düzenledim. Ve evet, C ++ 11'den itibaren bir yükümlülük var; bu C ++ 03'te örtüktü.
Yörüngedeki Hafiflik Yarışları

@xtofl: C ++ 03'te değil. C ++ 11'de, yine de orijinal cevapta kötüye kullanılan ön () ve back () işlevleriyle birlikte bu garantimiz var
Armen Tsirunyan

1
@Tomalak: İhtiyacınız olduğu için yanlış kullanıldılar &back() + 1, değil&back()
Armen Tsirunyan

12

Bu, bobobobo'nun cevabına bir yorum olarak daha iyi olurdu, ancak bunun için bir temsilcim yok. Aynı şeyi daha iyi uygulamalarla başarır.

Diğer cevaplar kullanışlı olmasına rağmen hiç dönüştürmek gerekiyorsa, std::stringhiç char*Kat olmadan açıkça, const_castsenin arkadaşın.

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

Bu edeceği Not değil size verilerin bir kopyasını vermek; size dize için bir işaretçi verecektir. Böylece, öğesinin bir öğesini değiştirirseniz chr, değiştirirsiniz str.


6

Giriş olarak geçmek için sadece bir C stili dizeye ihtiyacınız olduğunu varsayarsak:

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

4

Kesinlikle bilgiç olmak için, "std :: string'i bir char * veya char [] veri türüne dönüştüremezsiniz."

Diğer yanıtların gösterdiği gibi, std :: dizesinin içeriğini bir char dizisine kopyalayabilir veya "C stili" nden erişebilmeniz için std :: dizesinin içeriğine const char * yapabilirsiniz. .

Std :: string'in içeriğini değiştirmeye çalışıyorsanız, std :: string tipi, muhtemelen yapmanız gereken her şeyi yapmak için tüm yöntemlere sahiptir.

Char * alan bir işleve geçirmeye çalışıyorsanız, std :: string :: c_str () vardır.


4

İşte bir daha sağlam versiyonu 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

Dizenin boş olup olmadığını kontrol etmek için +1. Ben de dize sıfır sonlandığından emin olmak için bir kontrol eklemek istiyorum: if (str[str.length()-1] != 0) str.push_back(0)
GaspardP

4

OOP tarzında dönüşüm

converter.hpp

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

converter.cpp

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

kullanım

StringConverter::strToChar("converted string")

Nasıl oyuncular için döküm * c_str çıkışından const ortadan kaldırır gibi, ben c_str const char * döndürür neden şey salt okunur bir sürümünü sağlayarak, potansiyel bellek erişim sorunları ortadan kaldırmak olduğunu düşünüyorum. OP bir char sahip olmak istiyor *, ama bence daha güvenli çünkü ctst const char * çıktısı tarafından daha iyi hizmet olabilir, çünkü bu daha güvenli ve char * alan işlevler de genellikle const char * almak (fonksiyonları yok varsayarak) girdilerini değiştirmek gibi bir şey yapın, ki bunlar genel olarak yapmamalıdır).
Felipe Valdes

3

Bütünlük uğruna unutma std::string::copy().

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

str.copy(chrs, MAX);

std::string::copy()NUL sonlanmaz. C string işlevlerinde kullanmak için bir NUL sonlandırıcı sağlamanız gerekiyorsa:

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

memset(chrs, '\0', MAX);
str.copy(chrs, MAX-1);

3

Yineleyiciyi kullanarak yapabilirsiniz.

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

İyi şanslar.


3

Unique_ptr kullanarak orlp'nin char * yanıtının güvenli bir sürümü:

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

3

Bir elde etmek için const char *, bir gelen std::stringkullanımı c_str()elemanı işlevi:

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

Olmayan bir const elde etmek için char *bir mesafede std::stringkullanabilirsiniz data()C ++ 17 yana const olmayan işaretçi döndürür üye işlevi:

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

Dilin eski sürümlerinde, dizeyi sabit olmayan bir işaretçi elde edilebilecek bir vektöre kopyalamak için aralık yapısını kullanabilirsiniz:

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

Ancak bunun içerdiği dizeyi değiştirmenize izin vermeyeceğine dikkat edin str, yalnızca kopyanın verileri bu şekilde değiştirilebilir. Dilin eski sürümlerinde c_str()burada kullanılması özellikle önemlidir, çünkü o std::stringzamana kadar çağrılıncaya kadar boş sonlandırılacağı garanti edilmemiştir c_str().


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

2

Alternatif olarak, aşağıda gösterildiği gibi yazılabilir bir karakter * elde etmek için vektörleri kullanabilirsiniz;

//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  

Bu, vektör için yeni bellek tahsis eder ve ardından her karakteri kopyalar. std :: string zaten bir kapsayıcı, dizenize push_back (0) yapabilir ve & & str [0] yapabilirsiniz
GaspardP

1

Bu da işe yarayacak

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;  
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.