std :: string to char *

335

Я хочу преобразовать std :: string в тип данных char * или char [] .

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

Результат: «ошибка: невозможно преобразовать« std :: string »в« char »...» .

Какие методы доступны для этого?


источник

Ответы:

672

Он не будет автоматически конвертироваться (слава богу). Вы должны будете использовать метод, c_str()чтобы получить версию строки C.

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

Обратите внимание, что он возвращает const char *; вам не разрешено изменять строку в стиле C, возвращаемую c_str(). Если вы хотите обработать его, сначала скопируйте его:

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

Или в современном C ++:

std::vector<char> cstr(str.c_str(), str.c_str() + str.size() + 1);
orlp
источник
4
@Kerrek SB: Это был пример, который использовал бы умный указатель в реальном коде, или, скорее, полностью избежал этого c_strбезумия.
orlp
14
Ответ громоздкий, не элегантный, нелокальный, использует необработанные массивы и требует внимания к безопасности исключений. vectorбыл придуман именно как оболочка для динамических массивов, поэтому его использование в лучшем случае кажется упущенной возможностью, а в худшем - нарушением духа C ++.
Керрек С.Б.
21
Во-первых, да, ответ громоздкий. Сначала я объясняю ошибку ОП (думая, что std::stringэто автоматически преобразует), а затем объясняю, что он должен использовать, с коротким примером кода. Забегая вперед, я также объясню некоторые побочные эффекты использования этой функции, одна из которых заключается в том, что вы не можете редактировать возвращаемую строку c_str(). Вы ошибочно видите мои короткие примеры как реальный код для решения проблем, а это не так.
orlp
8
Я понизил ответ. Этот ответ действительно бесполезен, и тот факт, что он был принят, вызывает сожаление. В этом ответе полностью игнорируются хорошие практики программирования на C ++ и безопасность исключений, и существуют гораздо более совершенные решения, некоторые из которых приведены в других ответах на этот вопрос (например, ответ, который использует ildjarn, который использует std::vector<char>).
Джеймс МакНеллис
114
@ james-mcnellis, я выбрал этот ответ как правильный, потому что он ответил ТОЧНО на то, что я просил ... Не больше, не меньше. Я не спрашивал о том, что вы думаете, что я должен делать, я не просил другого решения о том, что вы думаете, что я делаю, я не просил о передовой практике. Вы не представляете, над чем я работаю, где будет реализован мой код и при каких условиях. Некоторые должны научиться читать, понимать вопросы и отвечать на то, что на самом деле задают. Не надо тут хвастаться.
151

Подробнее здесь и здесь, но вы можете использовать

string str = "some string" ;
char *cstr = &str[0];
bobobobo
источник
15
FWIW, в моей книге, это единственный правильный ответ на вопрос, который фактически был задан. Std :: string по своей сути изменчив: люди, которые делают это, похоже, изменяют содержимое строки, так или иначе, работа дьявола упускает этот факт.
Джей Фриман-Саурик-
2
да, это правильный ответ. глупо, что, учитывая частоту использования, для этого нет стандартного метода, такого как блокировка буфера в msoft.
Эрик Аронесты
1
Я изменил 0 на 0u. Потому что некоторые компиляторы / библиотеки будут (верите или нет) жаловаться на некоторую двусмысленность, когда предупреждения полностью включаются для конструкции & str [0]
Эрик Аронесты,
Я сомневаюсь, что при удалении str, char cstr обнуляется. Так что я думаю, что здесь указатель на символ назначается только указателю строки. Таким образом, преобразование строки в символ не является буквально полным. Строка указывает только на символ *, но ее значение не преобразуется. Я прав???
Самита Чатуранга
5
Обратите внимание, что это только C ++ 11. Предыдущие версии могут не иметь постоянного хранилища или пропустить завершающий
ноль
39

Если бы мне нужна изменяемая сырая копия строкового содержимого c ++, я бы сделал это:

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

и позже:

free(chr); 

Так почему бы мне не поиграться с std :: vector или new [] как кто-либо еще? Потому что, когда мне нужна изменяемая необработанная строка char * в стиле C, то, потому что я хочу вызвать код C, который изменяет строку, а код C освобождает вещи с помощью free () и выделяет с помощью malloc () (strdup использует malloc) . Поэтому, если я передам свою необработанную строку какой-либо функции X, написанной на C, у нее может быть ограничение на аргумент, который она должна разместить в куче (например, если функция может захотеть вызвать realloc для параметра). Но очень маловероятно, что он ожидал бы аргумент, выделенный (каким-то образом переопределенным пользователем) new []!

Скандинавский мэйнфрейм
источник
Вы должны объяснить, откуда strdup.
LF
22

(Этот ответ относится только к C ++ 98.)

Пожалуйста, не используйте сырье 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
Мне просто нужно было что-то подобное сегодня утром. Мне было интересно, это нормально говорить vector<char>(str.c_str(), str.c_str() + str.size() + 1), не назначая указатель на символ временный?
Kerrek SB
1
@Kerrek: Да, возвращаемое значение std::basic_string<>::c_str()действует до тех пор, пока не stringбудет изменено или уничтожено. Это также подразумевает, что оно возвращает то же значение при последующих вызовах, если stringоно не изменено.
ildjarn
2
@friendzis: Таким образом, вы не сможете использовать ни скорость, ни пространство vector. И если бы нужно было написать код, исключающий исключения, без механизма RAII (т. Е. С использованием необработанных указателей), сложность кода была бы намного выше, чем у этого простого однострочного.
ildjarn
7
Это миф, который vectorимеет огромное количество накладных расходов и сложности. Если вы требуете, чтобы у вас был изменяемый массив символов, то фактически вектор символов в значительной степени является идеальной оболочкой C ++. Если ваше требование на самом деле просто требует указателя const-char, просто используйте c_str()и все готово.
Керрек С.Б.
3
@ildjarn: На самом деле это было в принципе .
Гонки легкости на орбите
14
  • Если вам нужна строка в стиле C, представляющая тот же контент:

    char const* ca = str.c_str();
  • Если вам нужна строка в стиле C с новым содержимым, одним из способов (учитывая, что вы не знаете размер строки во время компиляции) является динамическое распределение:

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

    Не забудь об delete[]этом позже.

  • Если вам нужен статически размещенный массив ограниченной длины:

    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::stringнеявно преобразуется в эти типы по той простой причине, что для этого обычно требуется запах проекта. Убедитесь, что вам это действительно нужно.

Если вам определенно нужен char*, вероятно , лучший способ:

vector<char> v(str.begin(), str.end());
char* ca = &v[0]; // pointer to start of vector
Гонки легкости на орбите
источник
1
Почему &str.front(), &str.back()(которых нет в C ++ 03) вместо более распространенных str.begin()и str.end()?
Армен Цирунян
1
насчет str.begin(), или даже std::begin(str), итератор типа? Я не верю, stringчто обязан быть в смежных воспоминаниях vector, или это так?
xtofl
1
@xtofl: я уже редактировал их в. И да, в C ++ 11 есть обязательство; это подразумевалось в C ++ 03.
Гонки легкости на орбите
@xtofl: нет в C ++ 03. В C ++ 11 у нас есть эта гарантия, а также функции front () и back (), которые в любом случае неправильно использовались в исходном ответе
Армен Цирунян,
1
@ Томалак: Их неправильно использовали в том, что вам нужно &back() + 1, а не&back()
Армен Цирунян,
12

Это было бы лучше в качестве комментария к ответу Бобобо, но у меня нет представителя для этого. Это выполняет то же самое, но с лучшими практиками.

Хотя другие ответы полезны, если вам когда-либо понадобится явно преобразовать std::stringв char*const, const_castэто ваш друг.

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

Обратите внимание, что это не даст вам копию данных; это даст вам указатель на строку. Таким образом, если вы измените элемент chr, вы измените str.

hairlessbear
источник
6

Предполагая, что вам просто нужна строка в стиле C для передачи в качестве входных данных:

std::string str = "string";
const char* chr = str.c_str();
Марк Б
источник
4

Чтобы быть строго педантичным, вы не можете «преобразовать std :: string в тип данных char * или char []».

Как показали другие ответы, вы можете скопировать содержимое std :: string в массив char или сделать const char * для содержимого std :: string, чтобы получить к нему доступ в стиле «C» ,

Если вы пытаетесь изменить содержимое std :: string, тип std :: string имеет все методы, чтобы сделать все, что вам может понадобиться.

Если вы пытаетесь передать его какой-то функции, которая принимает char *, есть std :: string :: c_str ().

Роб К
источник
4

Вот еще одна надежная версия от 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
zangw
источник
+1 за проверку того, что строка пуста. Я также добавил бы проверку, чтобы убедиться, что строка заканчивается нулем: if (str[str.length()-1] != 0) str.push_back(0)
GaspardP
4

Преобразование в стиле ООП

converter.hpp

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

converter.cpp

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

использование

StringConverter::strToChar("converted string")
Патрик Мерчельски
источник
Мне нравится, как приведение к char * устраняет const из вывода c_str, я думаю, что причина, по которой c_str возвращает const char *, состоит в том, чтобы устранить потенциальные проблемы с доступом к памяти, предоставляя версию только для чтения. ОП хочет иметь символ *, но я думаю, что вместо него лучше использовать вывод const char * из c_str, поскольку это безопаснее, а функции, принимающие char *, обычно также принимают const char * (при условии, что функции этого не делают) делать что-то вроде изменения их входных данных, что в общем случае не должно).
Фелипе Вальдес
3

Ради полноты не забывайте std::string::copy().

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

str.copy(chrs, MAX);

std::string::copy()не NUL прекращать. Если вам нужно обеспечить терминатор NUL для использования в строковых функциях C:

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

memset(chrs, '\0', MAX);
str.copy(chrs, MAX-1);
Джеффри Томас
источник
3

Вы можете сделать это с помощью итератора.

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

Удачи.

TS.PARK
источник
3

Безопасная версия ответа char * orlp с использованием unique_ptr:

std::string str = "string";
auto cstr = std::make_unique<char[]>(str.length() + 1);
strcpy(cstr.get(), str.c_str());
Enhex
источник
3

Чтобы получить const char *из std::stringиспользования c_str()функцию-член:

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

Чтобы получить неконстантный char *объект из, std::stringвы можете использовать data()функцию-член, которая возвращает неконстантный указатель начиная с C ++ 17:

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

Для более старых версий языка вы можете использовать конструкцию диапазона, чтобы скопировать строку в вектор, из которого можно получить неконстантный указатель:

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

Но учтите, что это не позволит вам изменить строку, содержащуюся в этом str, только данные копии могут быть изменены таким образом. Обратите внимание, что это особенно важно в старых версиях языка, чтобы использовать c_str()здесь, потому что тогда std::stringне было гарантировано, что будет завершено нулем, пока не c_str()был вызван.

Франсуа Андриё
источник
2
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());
cegprakash
источник
2

Кроме того, вы можете использовать векторы, чтобы получить записываемый символ *, как показано ниже;

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

источник
Это выделит новую память для вектора, а затем скопирует каждый символ. std :: string уже является контейнером, вы можете также нажать push_back (0) на вашу строку и выполнить & str [0]
GaspardP
1

Это тоже будет работать

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;  
Genocide_Hoax
источник