Как преобразовать строку std::в const char* или char*?

как я могу преобразовать std::string до char* или const char*?

8 ответов


если вы просто хотите передать std::string для функции, которая нуждается const char* можно использовать

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

если вы хотите получить записываемую копию, например char *, вы можете сделать это с помощью этого:

std::string str;
char * writable = new char[str.size() + 1];
std::copy(str.begin(), str.end(), writable);
writable[str.size()] = ''; // don't forget the terminating 0

// don't forget to free the string after finished using it
delete[] writable;

редактировать: обратите внимание, что вышеизложенное не является исключением. Если что-нибудь между new звонок и delete вызов бросает, у вас будет утечка памяти, так как ничего не вызовет delete для вас автоматически. Есть два пути решения этот.

boost:: scoped_array

boost::scoped_array удалит память для вас при выходе из области:

std::string str;
boost::scoped_array<char> writable(new char[str.size() + 1]);
std::copy(str.begin(), str.end(), writable.get());
writable[str.size()] = ''; // 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

это стандартный способ (не требует никаких внешних библиотек). Вы используете std::vector, который полностью управляет памятью для вас.

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

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

дали сказать...

std::string x = "hello";

получение "char *" или "const char*" из "строки"

как получить указатель символов, который действителен в то время как x остается в области и не изменяется далее

C++11 упрощает вещи; следующие все дают доступ к тому же внутренний буфер строки:

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

все вышеперечисленные указатели будут содержать то же значение - адрес первого символ в буфере. Даже пустая строка имеет "первый символ в буфере", потому что C++11 гарантирует всегда сохранять дополнительный символ Nul/0 после явно назначенного содержимого строки (например,std::string("thisthat", 9) будет иметь буфер, удерживающий "thisthat").

учитывая любой из вышеперечисленных указателей:

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

только неconst указатель &x[0]:

p_x0_rw[n] = c;  // valid for n <= x.size() - 1
                 // i.e. don't overwrite the implementation maintained NUL

запись нуля в другом месте строки делает не изменить string ' s size(); string ' ы могут содержать любое количество нулей - они не получают специального обращения std::string (то же самое в C++03).

на C++03, все было значительно сложнее (ключевые отличия выделена):

  • x.data()

    • возвращает const char* во внутренний буфер строки что не требовалось стандартом для завершите нулем (т. е. может быть ['h', 'e', 'l', 'l', 'o'] с последующим неинициализированными или мусорными значениями, с случайным доступом к ним, имеющим неопределено поведение).
      • x.size() символы безопасны для чтения, т. е. x[0] через x[x.size() - 1]
      • для пустых строк вам гарантирован ненулевой указатель, к которому можно безопасно добавить 0 (ура!), но вы не должны разыменовать, что указатель.
  • &x[0]

    • для пустых строк это имеет неопределенное поведение (21.3.4)
      • например, учитывая f(const char* p, size_t n) { if (n == 0) return; ...whatever... } вы не должны называть f(&x[0], x.size());, когда x.empty() - просто используйте f(x.data(), ...).
    • в противном случае, согласно x.data() но:
      • для некурящихconst x это дает неconst char* указатель; вы можно перезаписать содержимое строки
  • x.c_str()

    • возвращает const char* к представлению ASCIIZ (Nul-terminated) значения (т. е. ['h', 'e', 'l', 'l', 'o', '\0']).
    • хотя немногие, если какие-либо реализации решили сделать это, стандарт C++03 был сформулирован, чтобы позволить реализации строки свободу создавать отдельный буфер с нулевым завершением на ходу, из потенциально ненулевого завершенного буфера "exposed"x.data() и &x[0]
    • x.size() + 1 символы безопасны для чтения.
    • гарантированный сейф даже для пустых строк (['\0']).

последствия доступа к внешним правовые показатели

каким бы образом вы ни получили указатель, вы не должны обращаться к памяти дальше от указателя, чем символы, гарантированные настоящим в описаниях выше. Попытки сделать это имеют неопределено поведение, С очень реальной вероятностью сбоев приложений и результатов мусора даже для чтения и, кроме того, оптовые данные, повреждение стека и / или уязвимости безопасности для записи.

когда эти указатели становятся недействительными?

если вы называете некоторые string функция-член, которая модифицирует string или резервирует дополнительную емкость, любые значения указателя, возвращенные заранее любым из вышеуказанные методы являются недействительным. Вы можете использовать эти методы снова, чтобы получить другой указатель. (Правила такие же, как для итераторов в strings).

см. также как получить указатель символов, действительный даже после x оставляет область действия или изменяется далее ниже....

так, что лучше использовать?

из C++11, использование .c_str() для данных ASCIIZ и .data() для "двоичных" данных (см. ниже).

в C++03, используйте .c_str() если не уверен, что .data() адекватно, и предпочитают .data() над &x[0] как это безопасно для пустых строк....

...попробуйте понять программу достаточно, чтобы использовать data() при необходимости, или вы, вероятно, сделаете другие ошибки...

символ ASCII NUL '\0', гарантированный .c_str() используется многими функциями в качестве значения sentinel, обозначающего конец соответствующих и безопасных для доступа данных. Это касается как C++-только как сказать fstream::fstream(const char* filename, ...) и функции shared-with-C, такие как strchr() и printf().

учитывая C++03's .c_str()гарантии о возвращенном буфере являются супер-набором .data(), вы всегда можете безопасно использовать .c_str(), но люди иногда этого не делают, потому что:

  • используя .data() связывается с другими программистами, читающими исходный код, что данные не ASCIIZ (скорее, вы используете строку для хранения блока данных (который иногда даже не является текстовым)), или что вы передаете его другой функции, которая рассматривает его как блок "двоичных" данных. Это может быть важным моментом в обеспечении того, чтобы изменения кода других программистов продолжали правильно обрабатывать данные.
  • C++03 только: есть небольшой шанс, что ваш string реализация должна будет сделать дополнительное выделение памяти и / или копирование данных, чтобы подготовить буфер с нулевым завершением

как далее подсказка, если параметры функции требуют (const) char* но не настаивайте на том, чтобы x.size() функция наверное требуется вход ASCIIZ, поэтому .c_str() - хороший выбор (функция должна знать, где текст каким-то образом заканчивается, поэтому, если это не отдельный параметр, это может быть только соглашение, такое как префикс длины или sentinel или некоторая фиксированная ожидаемая длина).

как получить указатель символов, действительный даже после x оставляет область видимости или изменяется далее

вам потребуется скопировать содержание string x к новой области памяти снаружи x. Этот внешний буфер может быть во многих местах, таких как другой string или переменная массива символов, она может иметь или не иметь другой срок службы, чем x из-за того, что он находится в другой области (например, пространство имен, глобальный, статический, куча, общая память, сопоставленный файл памяти).

Скопировать текст из std::string x в независимый массив символов:

// 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 == "abcd" -> 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->Hel)
char y[N + 1];
strncpy(y, x.c_str(), N);  // copy at most N, zero-padding if shorter
y[N] = '';               // 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* или const char* генерируется из string

Итак, выше вы видели, как получить (const) char*, а как сделать копию текста зависит от оригинала string, а как do с ним? Случайный набор примеров...

  • дайте коду " C " доступ к c++ stringтекст, как в printf("x is '%s'", x.c_str());
  • копировать x's текст в буфер, указанный вызывающим абонентом вашей функции (например,strncpy(callers_buffer, callers_buffer_size, x.c_str())) или изменчивая память, используемая для ввода-вывода устройства (например,for (const char* p = x.c_str(); *p; ++p) *p_device = *p;)
  • добавить xтекст в массив символов, уже содержащий некоторый текст ASCIIZ (например,strcat(other_buffer, x.c_str())) - будьте осторожны, чтобы не переполнять буфер (во многих ситуациях вам может потребоваться использовать strncat)
  • возвратить const char* или char* из функции (возможно, по историческим причинам-клиент использует ваш существующий API - или для C совместимость вы не хотите возвращать std::string, но хочу скопировать ваш stringданные где-то для вызывающего абонента)
    • будьте осторожны, чтобы не возвращать указатель, который может быть разыменованы абонента через местные string переменная, на которую указывал этот указатель, оставила область
    • некоторые проекты с общими объектами, скомпилированными / связанными для разных std::string реализации (например, STLport и собственный компилятор) могут передавать данные как ASCIIZ, чтобы избежать конфликты

использовать .c_str() метод const char *.

можно использовать &mystring[0] и char * указатель, но есть пара gotcha's: вы не обязательно получите строку с нулевым концом, и вы не сможете изменить размер строки. Вы особенно должны быть осторожны, чтобы не добавлять символы после конца строки, или вы получите переполнение буфера (и вероятный сбой).

не было никакой гарантии, что все символы будут частью одного и того же смежного буфера до C++11, но на практике все известные реализации std::string так или иначе, сработало; см. указывает ли "&s[0] " на непрерывные символы в строке std::?.

обратите внимание, что многие string функции-члены перераспределят внутренний буфер и аннулируют любые указатели, которые вы могли бы сохранить. Лучше сразу их использовать, а потом выбросить.


C++17

C++17 (предстоящий стандарт) изменяет синопсис шаблона basic_string добавление перегрузки non const data():

charT* data() noexcept;

возвращает: указатель p такой, что P + i == &оператор для каждого i в [0, size ()].


CharT const * С std::basic_string<CharT>

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

CharT * С std::basic_string<CharT>

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

C++11

CharT const * от std::basic_string<CharT>

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

CharT * С std::basic_string<CharT>

начиная с C++11, стандарт говорит:

  1. char-подобные объекты в ' не подлежит изменению / не обязательно является частью неконстантной памяти.
  2. 2. Использовать std::vector<CharT>

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

    Pro

  • простой
  • автоматическая обработка памяти
  • динамический

минусы

  • требуется string copy

3. Использовать std::array<CharT, N> если N является константой времени компиляции (и достаточно мала)

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

Pro

  • простой
  • стековой памяти обработка

минусы

  • статический
  • требуется string copy

4. Выделение необработанной памяти с автоматическим удалением хранилища

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

  • малый объем памяти
  • автоматическое удаление
  • простой

минусы

  • требует строку копия
  • Static (динамическое использование требует намного больше кода)
  • меньше функций, чем вектор или массив

5. Выделение необработанной памяти с ручной обработкой

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

  • требуется string copy
  • максимальная ответственность / восприимчивость к ошибки
  • комплекс

Я работаю с API с большим количеством функций get в качестве ввода a char*.

Я создал небольшой класс для решения такой проблемы, я реализовал идиому 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_; }
};

и вы можете использовать его как:

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

Я вызвал класс DeepString потому что он создает глубокую и уникальную копию (DeepString не копируется) существующей строки.


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

просто посмотрите:

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

однако , обратите внимание, что это вернет const char *.Для char * используйте strcpy скопировать его в другой char массив.


попробуй такое

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