Как я могу преобразовать std::string в char* или const char*?
Вы не можете использовать str.size (), если размер не известен во время компиляции, также он может переполнить ваш стек, если значение фиксированного размера огромно.
char * result = strcpy ((char *) malloc (str.length () + 1), str.c_str ());
@cegprakash strcpy и malloc на самом деле не подходят для C++.
@boycy: вы имеете в виду, что они вымышленные?
Нет, но char* dest = new char[str.length() + 1]; std::copy(str.begin(), str.end(), dest) был бы более идиоматическим C++. strcpy() и malloc() не являются ошибочными или проблематичными, но кажется непоследовательным использование строки C++ и средств библиотеки C с эквивалентами C++ в одном блоке кода.
stringName.c_str(), если это std::string, std::wstring или что-то вроде winrt::hstring.





Используйте метод .c_str() для const char *.
Вы можете использовать &mystring[0] для получения указателя char *, но есть пара подводных камней: вы не обязательно получите строку с нулевым завершением, и вы не сможете изменить размер строки. Вы особенно должны быть осторожны, чтобы не добавлять символы после конца строки, иначе вы получите переполнение буфера (и вероятный сбой).
До C++ 11 не было гарантии, что все символы будут частью одного и того же непрерывного буфера, но на практике все известные реализации std::string так или иначе работали; см. Указывает ли «& s [0]» на непрерывные символы в std :: string?.
Обратите внимание, что многие функции-члены string перераспределяют внутренний буфер и аннулируют любые указатели, которые вы могли сохранить. Лучше всего использовать их сразу, а затем выбросить.
вы должны заметить, что data () возвращает const char * :) то, что вы имеете в виду, это & str [0], которая возвращает непрерывную, но не обязательно строку с завершающим нулем.
@litb, Аргх! Вот что я получаю, пытаясь придумать быстрый ответ. Я использовал ваше решение в прошлом, не знаю, почему это не первое, что пришло в голову. Я отредактировал свой ответ.
Технически хранение std :: string будет непрерывным только в C++ 0x.
@MSalters, спасибо - я этого не знал. Однако мне было бы трудно найти реализацию, где этого не было бы.
char * результат = strcpy (malloc (str.length () + 1), str.c_str ());
Если вы просто хотите передать 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()] = '\0'; // 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 удалит память для вас при выходе из области видимости:
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, который полностью управляет памятью за вас.
std::string str;
std::vector<char> writable(str.begin(), str.end());
writable.push_back('\0');
// get the char* using &writable[0] or &*writable.begin()
Просто используйте char * result = strdup (str.c_str ());
вы могли бы, но strdup - это не стандартная функция c или C++, это от posix :)
я бы, вероятно, предпочел std :: vector <char> записываемый (str.begin (), str.end ()); Writable.push_back ('\ 0'); записываемый. char * c = & Writable [0];
Вы также можете создать вектор с помощью: vector <char> Writable (str.c_str (), str.size () + 1);
Определенно используйте std :: vector. Выделение массива char небезопасно.
Я согласен: litb, вы должны добавить свое "векторное" решение к своему основному ответу, так как оно (исключение) безопаснее, чем исходное решение new / delete.
Мне любопытно, почему вы наклоняетесь назад, чтобы использовать std :: copy (). Разве использование strcpy (the_destination, str.c_str ()) или strlcpy (), если оно у вас есть, также не сработало бы и не было бы более очевидным, что происходит? strcpy () будет работать с любым из scoped_array, vector или необработанным распределением памяти.
std :: copy - это способ сделать это в C++ без необходимости получать указатель на строку. Я стараюсь по возможности избегать использования функций C.
@efotinis: Какой конструктор векторов использует vector<char> writable(str.c_str(), str.size() + 1);?
@Paul Baker: Это воображаемый ctor, который я придумал :) Я перепутал его с ctor std :: string (или, может быть, это было нестандартное расширение VC6 ... содрогаться). В любом случае, мое предпочтительное решение - это то, что упомянуто в комментарии litb выше (с начальными / конечными элементами).
Кстати, если вы используете что-то вроде strdup (), вы должны вызвать free () позже (в отличие от delete []).
Я бы предположил, что это также «способ C++» - просто изменить std :: string на месте, поскольку его открытый интерфейс предоставляет char &operator[]: это заданное и гарантированное поведение.
char *p = const_cast<char*>(str.c_str()) - вариант (хоть и плохой)?
@LightnessRacesinOrbit Я был молод ... прости. :(
Вы должны добавить комментарий «НЕ ДЕЛАЙТЕ ЭТО» рядом с заявлением new char[..]. Я подозреваю, что многие люди просто копируют / вставляют образец кода, не читая сопроводительный текст.
Как новичок в C++, почему бы мне просто не использовать std :: strcpy (dest, str.c_str ())?
@Finster, это совершенно нормально, и, возможно, я бы использовал его и в реальном коде, когда торопился :) Мне просто нравится использовать std::copy, когда у меня есть время, чтобы сделать хороший код. Не будем забывать, что есть разница (хотя и маловероятная с настоящими строками - но кто знает, что он собирается хранить). std::copy также скопирует встроенные нулевые байты до конца std::string.
Почему бы не скопировать строку и передать & copy [0] для записываемого символа * фиксированного размера?
char * result = strcpy ((char *) malloc (str.length () + 1), str.c_str ());
Почему бы просто не использовать std::copy(str.begin(), str.end(), writable); writable[str.size()] = '\0'; вместо std::copy(str.begin(),str.end() + 1,writable);?
@rsethc, потому что в C++ 03 это было недопустимо. Я не уверен, что для этого есть точное правило в C++ 11 и C++ 14. Они гарантируют, что строка оканчивается нулем и является непрерывной, по крайней мере
Ах, так в 03 не было гарантировано наличие нулевого терминатора? Это имеет смысл.
@rsethc больше всего меня беспокоит end() + 1, а не нулевой терминатор (я не эксперт по библиотекам, но не думаю, что какая-либо из популярных сегодня реализаций библиотеки имеет std::string без завершающего \0). В отладочных сборках некоторые реализации библиотек имеют контейнеры, в которых .end() возвращает объект класса, который выдает / core-dumps на .end() + 1. Так что я лучше буду осторожен и напишу код, который точно знаю, работает :)
Это звучит невероятно расточительно, но я уверен, что для этого есть причина. Я очень редко использую стандартную библиотеку C++ и придерживаюсь C stdlib, поэтому у меня не было большой практики с ними. Можно было ожидать, что .end() вернет int размера указателя или что-то подобное.
Для первого блока кода выполняется глубокая или неглубокая копия?
Решения с участием strcpy() или strdup() могут потерпеть неудачу, если std::string содержит встроенные нулевые символы.
Вместо boost::scoped_array<char> можно также использовать std::unique_ptr<char[]> из STL: std::unique_ptr<char[]> writable(new char[str.size() + 1]);. Он также освобождает массив с помощью delete[], когда он выходит за пределы области видимости.
Начиная с C++ 17, std::string::data() теперь возвращает CharT* вместо const CharT*. Возможно, стоит обновить этот ответ :)
Учитывая, что проблемы с простым использованием data или &s[0] были исправлены для трех выпущенных языковых версий, все это кажется чрезмерно сложным. Даже если это строка const, ее простой копии должно быть достаточно.
std::unique_ptr<char[]> writable(str.size() + 1) можно использовать так же, как boost::scoped_arrayЯ работаю с API с множеством функций, получающих на входе 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 не копируется) существующей строки.
Я бы избегал этого соглашения об именах. c_str(), используемый std, является аббревиатурой от «C-string», а не «const string», и str() всегда возвращает std::basic_string, а не char* (например, std::stringstream::str()).
Просто посмотрите на это:
string str1("stackoverflow");
const char * str2 = str1.c_str();
Однако обратите внимание, что это вернет const char *.
Для char * используйте strcpy, чтобы скопировать его в другой массив char.
Привет, то, что вы опубликовали, уже было сказано несколько раз с более подробной информацией в других ответах на вопрос 5-летней давности. Ответить на старые вопросы можно, но только если вы добавите новую информацию. В остальном это просто шум.
Лично я ценю простоту.
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());
выглядит причудливо, но на самом деле сложно понять ... Простое - лучшее ИМО
strcpy (), malloc (), length () и c_str () - это базовые функции, и в этом нет ничего сложного. Просто выделение памяти и копирование.
да, функции простые, но вы их скрутили и согнули, чтобы они выглядели как миска со спагетти или монстр Франкенштейна в один лайнер :)
@cegprakash: всякий раз, когда есть malloc (), также должен быть free (). В противном случае код утечки памяти, как и решение в вашем ответе. Выделение памяти без хотя бы намека на требуемое освобождение - плохая практика для таких вопросов.
C++ 17 (будущий стандарт) изменяет синопсис шаблона basic_string, добавляя неконстантную перегрузку data():
charT* data() noexcept;Returns: A pointer p such that p + i == &operator for each i in [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();
CharT const * из std::basic_string<CharT>std::string str = { "..." };
str.c_str();
CharT * из std::basic_string<CharT>Начиная с C++ 11, стандарт гласит:
- The char-like objects in a
basic_stringobject shall be stored contiguously. That is, for anybasic_stringobjects, the identity&*(s.begin() + n) == &*s.begin() + nshall hold for all values ofnsuch that0 <= n < s.size().
const_reference operator[](size_type pos) const;reference operator[](size_type pos);Returns:
*(begin() + pos)ifpos < size(), otherwise a reference to an object of typeCharTwith valueCharT(); the referenced value shall not be modified.
const charT* c_str() const noexcept;const charT* data() const noexcept;Returns: A pointer p such that
p + i == &operator[](i)for eachiin[0,size()].
Есть несколько возможных способов получить указатель на неконстантный символ.
std::string foo{"text"};
auto p = &*foo.begin();
Pro
Минусы
'\0' не подлежит изменению / не обязательно является частью неконстантной памяти.std::vector<CharT>std::string foo{"text"};
std::vector<char> fcv(foo.data(), foo.data()+foo.size()+1u);
auto p = fcv.data();
Pro
Минусы
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
Минусы
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
Минусы
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
Против
Попробуй это
std::string s(reinterpret_cast<const char *>(Data), Size);
Вместо: char * Writable = new char [str.size () + 1]; Вы можете использовать char Writable [str.size () + 1]; Тогда вам не нужно беспокоиться об удалении записи или обработки исключений.