Nasıl std :: string const char * veya char * dönüştürmek için?


893

A'yı std::stringa char*veya a biçimine nasıl dönüştürebilirim const char*?


2
Bunun yerine: char * writable = new char [str.size () + 1]; Char writable [str.size () + 1]; O zaman yazılabilir veya istisna işleme hakkında endişelenmenize gerek yoktur.

7
Boyut derleme zamanında bilinmedikçe str.size () öğesini kullanamazsınız, ayrıca sabit boyut değeri çok büyükse yığınızı taşabilir.
paulm

1
char * sonuç = strcpy ((char *) malloc (str.length () + 1), str.c_str ());
cegprakash

7
@cegprakash strcpyve mallocgerçekten C ++ yolu değil.
boycy

4
Hayır, ama char* dest = new char[str.length() + 1]; std::copy(str.begin(), str.end(), dest)daha deyimsel C ++ olurdu. strcpy()ve malloc()yanlış veya sorunlu değil, ancak aynı kod bloğunda C ++ eşdeğerlerine sahip bir C ++ dize ve C kütüphane olanaklarının kullanılması tutarsız görünüyor.
boycy

Yanıtlar:


1055

Eğer sadece std::stringbir fonksiyona geçmek const char*istiyorsanız

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

Yazılabilir bir kopya almak istiyorsanız, örneğin char *, bunu şu şekilde yapabilirsiniz:

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;

Düzenleme : Yukarıdaki istisna güvenli değildir dikkat edin. newÇağrı ve çağrı arasında herhangi bir şey olursa delete, deleteotomatik olarak hiçbir şey çağırmayacağından bellek sızar . Bunu çözmenin iki acil yolu var.

boost :: scoped_array

boost::scoped_array kapsam dışına çıktığınızda belleği sizin için siler:

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

Bu standart yoldur (harici kütüphane gerektirmez). std::vectorHafızayı tamamen sizin için yöneten kullanıyorsunuz .

std::string str;
std::vector<char> writable(str.begin(), str.end());
writable.push_back('\0');

// get the char* using &writable[0] or &*writable.begin()

41
Char * sonuç = strdup (str.c_str ());
Jasper Bekkers

63
olabilir, ancak strdup ac veya c ++ standart işlevi değil, posix'ten :)
Johannes Schaub - litb

14
muhtemelen genellikle tercih ediyorum std :: vector <char> yazılabilir (str.begin (), str.end ()); writable.push_back ( '\ 0'); char * c = & yazılabilir [0];
Johannes Schaub - litb

17
std :: copy, dize işaretçisine ihtiyaç duymadan bunu yapmanın c ++ yoludur. C işlevlerini olabildiğince kullanmaktan kaçınmaya çalışıyorum.
Johannes Schaub - litb

16
C ++ 17'den itibaren std::string::data()artık a CharT*yerine bir const CharT*. Bu yanıtı güncellemek iyi bir fikir olabilir :)
Rakete1111

192

Diyelim ki ...

std::string x = "hello";

Bir dizeden `char *` ya da 'const char *' alma

xKapsamda kalmaya devam eden ve daha fazla değiştirilmeyen bir karakter işaretçisi nasıl edinilir

C ++ 11 işleri kolaylaştırır; aşağıdakilerin tümü aynı dahili dize arabelleğine erişim sağlar:

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

Yukarıdaki tüm işaretçiler aynı değeri tutacaktır - tampondaki ilk karakterin adresi. Boş bir dize bile "arabellekteki ilk karakter" e sahiptir, çünkü C ++ 11, açıkça atanan dize içeriğinden sonra her zaman fazladan bir NUL / 0 sonlandırıcı karakteri bulundurmayı garanti eder (örneğin std::string("this\0that", 9), bir tampon tutma özelliğine sahip olacaktır "this\0that\0").

Yukarıdaki işaretçilerden herhangi biri göz önüne alındığında:

char c = p[n];   // valid for n <= x.size()
                 // i.e. you can safely read the NUL at p[x.size()]

Sadece olmayan için constişaretçi p_writable_datave arasından &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

Dizede başka bir NUL yazma yok değil değiştirmek string'ın size(); stringherhangi bir sayıda NUL içermesine izin verilir - onlara özel bir tedavi verilmez std::string(C ++ 03 ile aynı).

In C ++ 03 , işler çok daha (önemli farklılıklar komplike edildi vurgulanan ):

  • x.data()

    • Standart tarafından bir NUL ile sonuçlanması gerekmeyenconst char* dizenin dahili arabelleğine döner (örneğin , tanımlanmamış davranışa sahip yanlışlıkla erişimleri olan, başlatılmamış veya çöp değerleri gelebilir ). ['h', 'e', 'l', 'l', 'o']
      • x.size()karakterleri okumak için güvenlidir, yani x[0]içindenx[x.size() - 1]
      • boş dizeler için, 0'ın güvenli bir şekilde eklenebileceği (yaşasın!) NULL olmayan bir işaretçi garantilidir, ancak bu işaretçiyi kullanmamanız gerekir.
  • &x[0]

    • boş dizeler için bunun tanımlanmamış davranışı vardır (21.3.4)
      • örneğin verilen f(const char* p, size_t n) { if (n == 0) return; ...whatever... }Eğer deme f(&x[0], x.size());zaman x.empty()sadece kullanmak - f(x.data(), ...).
    • aksi halde, x.data()ancak:
      • bunun için işaretçi const xolmayan bir sonuç verir const char*; dize içeriğinin üzerine yazabilirsiniz
  • x.c_str()

    • const char*değerin ASCIIZ (NUL sonlu) gösterimine geri döner (yani ['h', 'e', ​​'l', 'l', 'o', '\ 0']).
    • herhangi uygulamalar bunu seçerseniz kaç, C ++ 03 Standart bir oluşturmak için String Uygulama özgürlüğüne izin ifadeli rağmen ayrı boş karakter sonlandırmalı tampon anında potansiyel olmayan NUL dan, tarafından "maruz" tampon sonlandırıldı x.data()ve&x[0]
    • x.size() + 1 karakteri güvenle okuyabilirsiniz.
    • boş dizeler için bile güvenli (['\ 0']).

Yasal endekslerin dışına çıkmanın sonuçları

İşaretçiyi nereden alırsanız alın, yukarıdaki açıklamalarda bulunması garanti edilen karakterlerden daha fazla şekilde, işaretçiden itibaren belleğe erişmemeniz gerekir. Bunu yapmaya yönelik girişimler , okumalar için bile uygulama çökmeleri ve çöp sonuçlarının gerçek bir şansı ve ek olarak toptan veriler, yığın bozulması ve / veya yazma için güvenlik açıkları olan tanımsız davranışlara sahiptir .

Bu işaretçiler ne zaman geçersiz olur?

Daha fazla kapasiteyi stringdeğiştiren stringveya daha fazla kapasite ayıran bazı üye işlevlerini çağırırsanız , yukarıdaki yöntemlerden herhangi biri tarafından önceden döndürülen işaretçi değerleri geçersiz kılınır . Başka bir işaretçi almak için bu yöntemleri tekrar kullanabilirsiniz. (Kurallar, yineleyiciler için olanlarla aynıdır string).

Ayrıca , bir karakter işaretçisi xkapsamı terk ettikten sonra da geçerli kılmak veya aşağıda daha fazla değişiklik yapmak için bkz.

Peki hangisi daha iyi ?

C ++ 11'den .c_str()ASCIIZ verileri ve .data()"ikili" veriler (aşağıda daha ayrıntılı olarak açıklanmıştır) için kullanın.

C ++ 03, kullanım .c_str()belli olmadıkça .data()yeterli olduğunu ve tercih .data()üzerinde &x[0]boş dizeleri için güvenli olarak ....

... programı data()uygun olduğunda kullanmak için yeterince anlamaya çalışın , aksi takdirde muhtemelen başka hatalar yaparsınız ...

ASCII NUL '\ 0' karakteri .c_str(), birçok işlev tarafından, ilgili ve erişilmesi güvenli verilerin sonunu gösteren bir sentinel değeri olarak kullanılır. Bu hem C ++ için geçerlidir - yalnızca say fstream::fstream(const char* filename, ...)gibi işlevler strchr()ve, ve gibi C ile paylaşılan işlevler printf().

C ++ 03'ün .c_str()döndürülen arabellekle ilgili garantileri göz önüne alındığında .data(), her zaman güvenle kullanabilirsiniz .c_str(), ancak insanlar bazen şunları yapmaz:

  • kullanarak .data(), kaynak kodu okuyan diğer programcılarla iletişim kurarak verilerin ASCIIZ olmadığını (bunun yerine, bir veri bloğunu saklamak için dizeyi kullanıyorsunuz (bazen gerçekte metinsel bile değildir) veya "ikili" veri bloğu olarak değerlendiren başka bir işlev. Bu, diğer programcıların kod değişikliklerinin verileri düzgün işlemeye devam etmesini sağlama konusunda önemli bir fikir olabilir.
  • Yalnızca C ++ 03: stringNUL sonlandırılmış arabelleği hazırlamak için uygulamanızın birazdan fazladan bellek ayırma ve / veya veri kopyalama yapması gerekecektir.

Başka bir ipucu olarak, bir işlevin parametreleri ( const) gerektiriyor char*ancak alma konusunda ısrar etmiyorsa x.size(), işlev muhtemelen bir ASCIIZ girişine ihtiyaç duyar, bu nedenle .c_str()iyi bir seçimdir (işlev, metnin bir şekilde nerede sona erdiğini bilmelidir, bu yüzden değilse ayrı bir parametre yalnızca uzunluk öneki veya sentinel veya sabit bir beklenen uzunluk gibi bir kural olabilir).

Bir karakter işaretçisi xkapsamı terk ettikten veya daha sonra değiştirildikten sonra bile geçerli hale getirme

Öğesinin içeriğini dışarıdaki yeni bir bellek alanına kopyalamanız gerekir . Bu harici arabellek, başka bir karakter veya karakter dizisi değişkeni gibi birçok yerde olabilir, farklı bir kapsamda olmasından (örneğin ad alanı, genel, statik, yığın, paylaşılan bellek, bellek eşlenmiş dosya) farklı bir ömre sahip olabilir veya olmayabilir. .string xxstringx

Metni std::string xbağımsız bir karakter dizisine kopyalamak için :

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

Diğer nedenler istemek için char*ya const char*a oluşturulanstring

Gördüğünüz yukarıdaki Peki, nasıl bir (olsun const) char*, ve nasıl orijinal metin bağımsız bir kopyasını yapmak için string, ama ne olabilir yapmak onunla? Örneklerin rastgele dağılması ...

  • olduğu gibi C ++ stringmetnine "C" kodu erişimi verinprintf("x is '%s'", x.c_str());
  • xmetnini işlevinizin arayanı tarafından belirtilen bir ara belleğe kopyalayın (örn. strncpy(callers_buffer, callers_buffer_size, x.c_str())) veya cihaz G / Ç'si için kullanılan geçici belleğe (ör. for (const char* p = x.c_str(); *p; ++p) *p_device = *p;)
  • Append xzaten bazı ASCIIZ metni (örneğin içeren bir karakter dizisine 'in metin strcat(other_buffer, x.c_str())tampon taşması dikkat edin (birçok durumda size kullanım gerekebilir -) strncat)
  • bir işlevden const char*veya char*bir işlevden döndürme (belki geçmiş nedenlerden ötürü - müşteri mevcut API'nızı kullanıyorsa - veya C uyumluluğu için geri dönmek istemiyorsunuz std::string, ancak stringarayan kişinin verilerini bir yere kopyalamak istiyorsunuz )
    • stringİşaretçinin işaret ettiği yerel bir değişkenin kapsam dışına çıkmasından sonra arayan tarafından geri çevrilebilecek bir işaretçiyi döndürmemeye dikkat edin
    • farklı std::stringuygulamalar için derlenmiş / bağlantılı (örneğin, STLport ve derleyici-yerel) paylaşılan nesnelerin bulunduğu bazı projeler çakışmaları önlemek için verileri ASCIIZ olarak geçirebilir

4
Güzel bir. Char * (const olmayan) istemenin başka bir nedeni de MPI yayını ile çalışmaktır. İleri geri kopyalamanız gerekmiyorsa daha hoş görünüyor. Şahsen bir char * const alıcı dize teklif olurdu. Sabit işaretçi, ancak düzenlenebilir dize. Her ne kadar const char * dizeden örtük dönüşüm berbat olabilir ...
bartgol

33

.c_str()Yöntemini kullanın const char *.

&mystring[0]Bir char *işaretçi elde etmek için kullanabilirsiniz , ancak birkaç gotcha vardır: mutlaka sıfır sonlandırılmış bir dize elde edemezsiniz ve dizenin boyutunu değiştiremezsiniz. Özellikle dizenin sonuna kadar karakter eklememeye dikkat etmelisiniz yoksa arabellek taşması (ve olası çökme) elde edersiniz.

C ++ 11'e kadar tüm karakterlerin aynı bitişik tamponun bir parçası olacağına dair bir garanti yoktu, ancak pratikte std::stringzaten bilinen tüm bu şekilde uygulamalar bu şekilde çalıştı; bkz. “& s [0]” bir std :: dizesindeki bitişik karakterleri gösteriyor mu? .

Birçok stringüye işlevinin dahili arabelleği yeniden tahsis edeceğini ve kaydetmiş olabileceğiniz tüm işaretçileri geçersiz kılacağını unutmayın . Bunları hemen kullanmak ve sonra atmak en iyisidir.


1
data () ifadesinin const char * :) döndürdüğünü ve bitişik, ancak boş null sonlandırılmış bir dize döndürmeyen & str [0] olduğunu unutmayın.
Johannes Schaub - litb

1
@litb, Argh! Hızlı bir cevap vermeye çalıştığım şey bu. Çözümünüzü geçmişte kullandım, akla ilk gelen şeyin neden olmadığını bilmiyorum. Cevabımı düzenledim.
Mark Ransom

2
Teknik olarak, std :: string depolama yalnızca C ++ 0x ile bitişik olacaktır.
MSalters

1
@MSalters, teşekkürler - Bunu bilmiyordum. Yine de durumun böyle olmadığı bir uygulama bulmakta zorlanıyordum.
Mark Ransom

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

21

C ++ 17

C ++ 17 (yaklaşan standart), şablonun özetini değiştirerek, basic_stringsabit olmayan bir aşırı yük ekler data():

charT* data() noexcept;

Döndürür: [0, size ()] içindeki her i için p + i == & operatörü olacak şekilde bir işaretçi p.


CharT const * itibaren std::basic_string<CharT>

std::string const cstr = { "..." };
char const * p = cstr.data(); // or .c_str()

CharT * itibaren std::basic_string<CharT>

std::string str = { "..." };
char * p = str.data();

C ++ 11

CharT const * itibaren std::basic_string<CharT>

std::string str = { "..." };
str.c_str();

CharT * itibaren std::basic_string<CharT>

C ++ 11'den itibaren standart şöyle diyor:

  1. Bir cisimdeki karakter benzeri nesneler basic_stringbitişik olarak saklanacaktır. Yani, herhangi bir basic_stringnesne için s, kimlik böyle bir &*(s.begin() + n) == &*s.begin() + ndeğerin tüm değerleri için geçerli olacaktır .n0 <= n < s.size()

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

    Döndürür: *(begin() + pos)if pos < size(), aksi takdirde CharTdeğeri olan türdeki bir nesneye başvuru CharT(); atıfta bulunulan değer değiştirilemez.


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

    Döndürür: p + i == &operator[](i)Her igiriş için bir işaretçi p [0,size()].

Sabit olmayan bir karakter işaretçisi elde etmenin birçok olası yolu vardır.

1. C ++ 11'in bitişik depolamasını kullanın

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

profesyonel

  • Basit ve kısa
  • Hızlı (yalnızca kopya içermeyen yöntem)

Eksileri

  • Final '\0'değişmez / sabit olmayan belleğin bir parçası olmak zorunda değildir.

2. Kullanım std::vector<CharT>

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

profesyonel

  • Basit
  • Otomatik bellek kullanımı
  • Dinamik

Eksileri

  • Dize kopyası gerektirir

3. std::array<CharT, N>Eğer Nderleme zamanı sabiti (ve yeterince küçük) olan

std::string foo{"text"};
std::array<char, 5u> fca;
std::copy(foo.data(), foo.data()+foo.size()+1u, fca.begin());

profesyonel

  • Basit
  • Yığın bellek kullanımı

Eksileri

  • Statik
  • Dize kopyası gerektirir

Otomatik depolama silme ile 4. Ham bellek ayırma

std::string foo{ "text" };
auto p = std::make_unique<char[]>(foo.size()+1u);
std::copy(foo.data(), foo.data() + foo.size() + 1u, &p[0]);

profesyonel

  • Küçük bellek alanı
  • Otomatik silme
  • Basit

Eksileri

  • Dize kopyası gerektirir
  • Statik (dinamik kullanım çok daha fazla kod gerektirir)
  • Vektör veya diziden daha az özellik

Manuel işleme ile 5. Ham bellek tahsisi

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;
}

profesyonel

  • Maksimum 'kontrol'

aleyhte

  • Dize kopyası gerektirir
  • Hatalar için maksimum sorumluluk / duyarlılık
  • karmaşık

9

Ben bir girdi olarak almak fonksiyonları bir sürü API ile çalışıyorum a char*.

Bu tür sorunlarla yüzleşmek için küçük bir sınıf yarattım, RAII deyimini uyguladım.

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_; }
};

Ve şu şekilde kullanabilirsiniz:

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

Mevcut bir dizenin DeepString(kopyalanamaz) derin ve benzersiz bir kopyasını oluşturduğu için sınıfı çağırdım DeepString.


3
Bu adlandırma kuralından kaçınırdım. c_str()tarafından kullanılan std"Cı-string" değil "sabit string" için bir kısaltmadır ve str()her bir döner std::basic_stringdeğil char*(örneğin std::stringstream::str())
bcrist

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

1
süslü görünüyor ama anlaşılması gerçekten zor ... Basit en iyi IMO
Naeem A. Malik

4
strcpy (), malloc (), length () ve c_str () temel işlevlerdir ve bu konuda zor bir şey yoktur. Sadece bellek ayırma ve kopyalama.
cegprakash

5
evet fonksiyonlar temel ama onları spagetti veya bir astar Frankenstein'ın canavarı gibi görünmek için
Naeem A. Malik

4
Evet fonksiyonlar basit ama ... bir programlama diliyle uğraşmaya başladığınızı hatırladınız mı? Bazı satırlar açıklamak için daha fazla ve bir neofitin örneğin neden bu cevaptan farklı veya daha iyi olduğunu öğrenmesine gerçekten yardımcı olacak :)
Hastur

2
@cegprakash: Bir malloc () olduğunda, bir de ücretsiz () olması gerekir. Aksi takdirde kod hafızayı sızdırıyor ve cevabınızdaki çözüm de öyle. En azından gerekli anlaşmalara işaret etmeden bellek ayırmak bu tür sorular için kötü bir uygulamadır.
Striezel

7

Sadece şunu gör:

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

Ancak, bunun a döndüreceğini unutmayın const char *.

A için bunu başka bir diziye kopyalamak için char *kullanın .strcpychar


23
Merhaba, yayınladığınız şey, 5 yaşındaki sorunun diğer cevaplarında, daha fazla ayrıntıyla zaten birkaç kez söylendi. Eski soruları yanıtlamak iyidir, ancak yalnızca yeni bilgi eklerseniz. Aksi takdirde, sadece gürültü.
Mat

7
Şahsen, basitliği takdir ediyorum.
TankorSmash

-4

Bunu dene

std::string s(reinterpret_cast<const char *>(Data), Size);
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.