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

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

Вместо: char * Writable = new char [str.size () + 1]; Вы можете использовать char Writable [str.size () + 1]; Тогда вам не нужно беспокоиться об удалении записи или обработки исключений.

user372024 21.06.2010 13:34

Вы не можете использовать str.size (), если размер не известен во время компиляции, также он может переполнить ваш стек, если значение фиксированного размера огромно.

paulm 05.10.2012 19:32

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

cegprakash 12.07.2014 16:10

@cegprakash strcpy и malloc на самом деле не подходят для C++.

boycy 25.09.2014 13:29

@boycy: вы имеете в виду, что они вымышленные?

cegprakash 26.09.2014 04:45

Нет, но char* dest = new char[str.length() + 1]; std::copy(str.begin(), str.end(), dest) был бы более идиоматическим C++. strcpy() и malloc() не являются ошибочными или проблематичными, но кажется непоследовательным использование строки C++ и средств библиотеки C с эквивалентами C++ в одном блоке кода.

boycy 27.09.2014 12:38
stringName.c_str(), если это std::string, std::wstring или что-то вроде winrt::hstring.
kayleeFrye_onDeck 30.01.2019 05:14
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
947
7
1 004 431
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Используйте метод .c_str() для const char *.

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

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

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

вы должны заметить, что data () возвращает const char * :) то, что вы имеете в виду, это & ​​str [0], которая возвращает непрерывную, но не обязательно строку с завершающим нулем.

Johannes Schaub - litb 07.12.2008 22:44

@litb, Аргх! Вот что я получаю, пытаясь придумать быстрый ответ. Я использовал ваше решение в прошлом, не знаю, почему это не первое, что пришло в голову. Я отредактировал свой ответ.

Mark Ransom 07.12.2008 22:54

Технически хранение std :: string будет непрерывным только в C++ 0x.

MSalters 08.12.2008 13:04

@MSalters, спасибо - я этого не знал. Однако мне было бы трудно найти реализацию, где этого не было бы.

Mark Ransom 08.12.2008 23:04

char * результат = strcpy (malloc (str.length () + 1), str.c_str ());

cegprakash 12.07.2014 16:05
Ответ принят как подходящий

Если вы просто хотите передать 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

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::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 ());

Jasper Bekkers 07.12.2008 23:33

вы могли бы, но strdup - это не стандартная функция c или C++, это от posix :)

Johannes Schaub - litb 07.12.2008 23:39

я бы, вероятно, предпочел std :: vector <char> записываемый (str.begin (), str.end ()); Writable.push_back ('\ 0'); записываемый. char * c = & Writable [0];

Johannes Schaub - litb 07.12.2008 23:42

Вы также можете создать вектор с помощью: vector <char> Writable (str.c_str (), str.size () + 1);

efotinis 08.12.2008 00:08

Определенно используйте std :: vector. Выделение массива char небезопасно.

Martin York 08.12.2008 07:07

Я согласен: litb, вы должны добавить свое "векторное" решение к своему основному ответу, так как оно (исключение) безопаснее, чем исходное решение new / delete.

paercebal 10.12.2008 02:13

Мне любопытно, почему вы наклоняетесь назад, чтобы использовать std :: copy (). Разве использование strcpy (the_destination, str.c_str ()) или strlcpy (), если оно у вас есть, также не сработало бы и не было бы более очевидным, что происходит? strcpy () будет работать с любым из scoped_array, vector или необработанным распределением памяти.

Michael Burr 10.12.2008 03:33

std :: copy - это способ сделать это в C++ без необходимости получать указатель на строку. Я стараюсь по возможности избегать использования функций C.

Johannes Schaub - litb 10.12.2008 06:29

@efotinis: Какой конструктор векторов использует vector<char> writable(str.c_str(), str.size() + 1);?

user200783 11.11.2010 13:13

@Paul Baker: Это воображаемый ctor, который я придумал :) Я перепутал его с ctor std :: string (или, может быть, это было нестандартное расширение VC6 ... содрогаться). В любом случае, мое предпочтительное решение - это то, что упомянуто в комментарии litb выше (с начальными / конечными элементами).

efotinis 13.11.2010 12:06

Кстати, если вы используете что-то вроде strdup (), вы должны вызвать free () позже (в отличие от delete []).

njamesp 18.05.2012 03:05

Я бы предположил, что это также «способ C++» - просто изменить std :: string на месте, поскольку его открытый интерфейс предоставляет char &operator[]: это заданное и гарантированное поведение.

dmw 28.01.2013 14:10

char *p = const_cast<char*>(str.c_str()) - вариант (хоть и плохой)?

0x499602D2 19.02.2013 04:56

@LightnessRacesinOrbit Я был молод ... прости. :(

0x499602D2 29.01.2014 23:53

Вы должны добавить комментарий «НЕ ДЕЛАЙТЕ ЭТО» рядом с заявлением new char[..]. Я подозреваю, что многие люди просто копируют / вставляют образец кода, не читая сопроводительный текст.

StackedCrooked 15.03.2014 04:06

Как новичок в C++, почему бы мне просто не использовать std :: strcpy (dest, str.c_str ())?

Finster 19.04.2014 01:20

@Finster, это совершенно нормально, и, возможно, я бы использовал его и в реальном коде, когда торопился :) Мне просто нравится использовать std::copy, когда у меня есть время, чтобы сделать хороший код. Не будем забывать, что есть разница (хотя и маловероятная с настоящими строками - но кто знает, что он собирается хранить). std::copy также скопирует встроенные нулевые байты до конца std::string.

Johannes Schaub - litb 19.04.2014 02:26

Почему бы не скопировать строку и передать & copy [0] для записываемого символа * фиксированного размера?

Nick 07.05.2014 14:15

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

cegprakash 12.07.2014 16:08

Почему бы просто не использовать std::copy(str.begin(), str.end(), writable); writable[str.size()] = '\0'; вместо std::copy(str.begin(),str.end() + 1,writable);?

rsethc 02.09.2014 16:07

@rsethc, потому что в C++ 03 это было недопустимо. Я не уверен, что для этого есть точное правило в C++ 11 и C++ 14. Они гарантируют, что строка оканчивается нулем и является непрерывной, по крайней мере

Johannes Schaub - litb 02.09.2014 21:39

Ах, так в 03 не было гарантировано наличие нулевого терминатора? Это имеет смысл.

rsethc 02.09.2014 22:55

@rsethc больше всего меня беспокоит end() + 1, а не нулевой терминатор (я не эксперт по библиотекам, но не думаю, что какая-либо из популярных сегодня реализаций библиотеки имеет std::string без завершающего \0). В отладочных сборках некоторые реализации библиотек имеют контейнеры, в которых .end() возвращает объект класса, который выдает / core-dumps на .end() + 1. Так что я лучше буду осторожен и напишу код, который точно знаю, работает :)

Johannes Schaub - litb 03.09.2014 00:21

Это звучит невероятно расточительно, но я уверен, что для этого есть причина. Я очень редко использую стандартную библиотеку C++ и придерживаюсь C stdlib, поэтому у меня не было большой практики с ними. Можно было ожидать, что .end() вернет int размера указателя или что-то подобное.

rsethc 03.09.2014 07:01

Для первого блока кода выполняется глубокая или неглубокая копия?

user1197918 21.01.2015 04:41

Решения с участием strcpy() или strdup() могут потерпеть неудачу, если std::string содержит встроенные нулевые символы.

Keith Thompson 04.11.2015 00:13

Вместо boost::scoped_array<char> можно также использовать std::unique_ptr<char[]> из STL: std::unique_ptr<char[]> writable(new char[str.size() + 1]);. Он также освобождает массив с помощью delete[], когда он выходит за пределы области видимости.

tmlen 06.06.2016 14:25

Начиная с C++ 17, std::string::data() теперь возвращает CharT* вместо const CharT*. Возможно, стоит обновить этот ответ :)

Rakete1111 31.03.2017 15:06

Учитывая, что проблемы с простым использованием data или &s[0] были исправлены для трех выпущенных языковых версий, все это кажется чрезмерно сложным. Даже если это строка const, ее простой копии должно быть достаточно.

Leushenko 01.06.2018 16:54
std::unique_ptr<char[]> writable(str.size() + 1) можно использовать так же, как boost::scoped_array
tmlen 31.10.2020 23:52

Я работаю с 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()).

bcrist 06.09.2015 01:27

Просто посмотрите на это:

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

Однако обратите внимание, что это вернет const char *.

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

Привет, то, что вы опубликовали, уже было сказано несколько раз с более подробной информацией в других ответах на вопрос 5-летней давности. Ответить на старые вопросы можно, но только если вы добавите новую информацию. В остальном это просто шум.

Mat 12.05.2013 12:21

Лично я ценю простоту.

TankorSmash 19.04.2014 00:27
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());

выглядит причудливо, но на самом деле сложно понять ... Простое - лучшее ИМО

Naeem A. Malik 15.12.2014 14:53

strcpy (), malloc (), length () и c_str () - это базовые функции, и в этом нет ничего сложного. Просто выделение памяти и копирование.

cegprakash 17.12.2014 11:55

да, функции простые, но вы их скрутили и согнули, чтобы они выглядели как миска со спагетти или монстр Франкенштейна в один лайнер :)

Naeem A. Malik 17.12.2014 23:41
Да, функции простые, но ... вы помнили, когда начали заниматься языком программирования? Еще несколько строк, чтобы объяснить, и это действительно поможет новичку узнать, почему, например, он отличается от этот ответ или лучше :)
Hastur 25.09.2015 15:08

@cegprakash: всякий раз, когда есть malloc (), также должен быть free (). В противном случае код утечки памяти, как и решение в вашем ответе. Выделение памяти без хотя бы намека на требуемое освобождение - плохая практика для таких вопросов.

Striezel 23.08.2016 22:03

C++ 17

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

C++ 11

CharT const * из std::basic_string<CharT>

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

CharT * из std::basic_string<CharT>

Начиная с C++ 11, стандарт гласит:

  1. The char-like objects in a basic_string object shall be stored contiguously. That is, for any basic_string object s, the identity &*(s.begin() + n) == &*s.begin() + n shall hold for all values of n such that 0 <= n < s.size().

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

    Returns: *(begin() + pos) if pos < size(), otherwise a reference to an object of type CharT with value CharT(); the referenced value shall not be modified.


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

    Returns: A pointer p such that p + i == &operator[](i) for each i in [0,size()].

Есть несколько возможных способов получить указатель на неконстантный символ.

1. Используйте непрерывное хранилище C++ 11

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

Pro

  • Просто и коротко
  • Быстро (только метод без копирования)

Минусы

  • Окончательный '\0' не подлежит изменению / не обязательно является частью неконстантной памяти.

2. Используйте std::vector<CharT>

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

Pro

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

Минусы

  • Требуется копия строки

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

  • Простой
  • Работа с памятью стека

Минусы

  • Статический
  • Требуется копия строки

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

  • Небольшой объем памяти
  • Автоматическое удаление
  • Простой

Минусы

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

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

  • Максимальный контроль

Против

  • Требуется копия строки
  • Максимальная ответственность / восприимчивость к ошибкам
  • Сложный

Попробуй это

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

Другие вопросы по теме