std :: рядок до char *


335

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

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

Результати в: "помилка: не вдається перетворити 'std :: string' в 'char' ..." .

Які методи доступні для цього?

c++  string  char 

Відповіді:


672

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

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

Зауважте, що він повертає a 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);

4
@Kerrek SB: Це був приклад: можна використовувати розумний вказівник у реальному коді або, швидше за все, уникнути цього c_strбезумства повністю.
orlp

14
Відповідь об'ємна, неелегантна, не локальна, використовує необроблені масиви і вимагає уваги до безпеки виключень. vectorбув винайдений саме як обгортка для динамічних масивів, тому не використовувати це, мабуть, як упущену можливість, а в кращому випадку - з порушенням духу C ++.
Керрек СБ

21
Перш за все, так, відповідь є об’ємною. Спочатку я пояснюю помилку ОП (думаючи, що std::stringавтоматично перетвориться), а потім пояснюю, що він повинен використовувати, з коротким зразком коду. Розмірковуючи вперед, я також пояснюю деякі побічні ефекти від використання цієї функції, з яких один полягає в тому, що ви не можете редагувати рядок, який повертається c_str(). Ви помилково бачите мої короткі приклади як справжній код вирішення проблем, який це не так.
orlp

8
Я відповів на відповідь. Ця відповідь справді не є корисною, і той факт, що її прийняли, є найбільш прикрою. Ця відповідь повністю ігнорує добру практику програмування на C ++ та безпеку винятків, і є набагато переважніші рішення, деякі з яких наведені в інших відповідях на це питання (наприклад, відповіді, які дає ildjarn, який використовує std::vector<char>).
Джеймс Мак-Нілліс

114
@ james-mcnellis, я вибрав цю відповідь як правильну, тому що вона відповіла ТОЧНО, про що я просив ... Ні більше, ні менше. Я не питав, що ви думаєте, що я повинен зробити, я не просив іншого рішення для того, що ви думаєте, що я роблю, я не просив передового досвіду. Ви не маєте поняття над тим, над чим я працюю, де буде впроваджений мій код та за яких умов. Деякі повинні навчитися читати, розуміти питання та відповідати на те, що насправді задають. Тут не потрібно показуватись.

150

Детальніше тут , і тут, але ви можете використовувати

string str = "some string" ;
char *cstr = &str[0];

15
FWIW, в моїй книзі, це єдина правильна відповідь на питання, яке насправді було задано. Std :: string по суті є змінним: людям, які створюють це звучання, як зміна вмісту рядка, якимось чином дивовижній роботі здається, що цього факту не вистачає.
Джей Фріман -саурік-

2
так, це правильна відповідь. нерозумно, що, зважаючи на частоту використання, не існує стандартного методу для цього, як, наприклад, фіксатор msoft.
Ерік Аронестій

1
Я змінив 0 на 0u. Оскільки деякі компілятори / бібліотеки будуть (вірити чи ні) скаржитися на деяку неоднозначність, коли попередження будуть увімкнені повністю до конструкції & str [0]
Ерік Аронесті,

Я сумніваюсь, коли str буде видалено, char cstr робиться недійсним. Тому я думаю, тут лише покажчик рядка призначений покажчику char. Тож перетворення рядка в char не є буквально завершеним. Рядок вказується лише на char *, але його значення не перетворюється. Я прав?
Саміта Чатуранга

5
Зауважте, що це лише C ++ 11. Попередні версії можуть не мати постійного зберігання або не вистачає завершального нуля
Flamefire

40

Якщо мені знадобиться змінна необроблена копія вмісту рядка 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 за параметром). Але малоймовірно, що він очікує аргументу, виділеного з (деяким переробленим користувачем) новим []!


Ви повинні пояснити, звідки 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), не призначаючи покажчик чару тимчасовому?
Керрек СБ

1
@Kerrek: Так, повернене значення std::basic_string<>::c_str()є дійсним, поки значення не stringбуде змінено або знищено. Це також означає, що він повертає те саме значення для наступних дзвінків, поки stringне буде змінено.
ildjarn

2
@friendzis: Таким чином, немає швидкості та простору накладних витрат vector. І якби писати безпечний для винятку код без механізму RAII (тобто, використовуючи необроблені покажчики), складність коду була б набагато вищою, ніж цей простий однолінійний.
ildjarn

7
Це міф, який vectorмає величезну кількість накладних витрат і складність. Якщо ваша вимога полягає в тому, що у вас є змінний масив char, то насправді вектор символів - це майже ідеальна обгортка C ++. Якщо ваша вимога насправді просто вимагає вказівника const-char, тоді просто використовуйте c_str()і все закінчено.
Керрек СБ


15
  • Якщо ви просто хочете рядок у стилі С, що містить однаковий вміст:

    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: Не в С ++ 03. У C ++ 11 у нас є ця гарантія, а також функції передньої () та задньої (), які в будь-якому випадку не використовувались у початковій відповіді
Армен Цирунян

1
@Tomalak: Неправильно використовували їх у тому, що тобі потрібно &back() + 1,&back()
Армен Цирунян

12

Це було б краще, як коментар до відповіді bobobobo, але у мене немає відповіді на це. Це здійснює те саме, але з кращими методами.

Хоча інші відповіді корисні, якщо ви коли - небудь потрібно перетворити std::stringв char*явному вигляді без сопзЬ, const_castє вашим другом.

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

Зауважте, що це не дасть вам копії даних; це дасть вам вказівник на рядок. Таким чином, якщо ви модифікуєте елемент chr, ви модифікуєте str.


7

Якщо припустити, що вам просто потрібна рядок у стилі С, щоб перейти як вхід:

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

5

Щоб бути строго педантичним, ви не можете "перетворити std :: string у тип даних char * або char []."

Як показали інші відповіді, ви можете скопіювати вміст рядка std :: в масив char, або зробити const char * до вмісту рядка std ::, щоб ви могли отримати доступ до нього в "C стилі" .

Якщо ви намагаєтесь змінити вміст std :: string, тип std :: string має всі методи для того, щоб зробити все, що вам може знадобитися для цього.

Якщо ви намагаєтеся передати його якій-небудь функції, яка займає знак *, є std :: string :: c_str ().


4

Для повноти, не забувайте 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);

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

+1 для перевірки того, що рядок порожній. Я також додав би чек, щоб переконатися, що рядок завершено нулем: if (str[str.length()-1] != 0) str.push_back(0)
GaspardP

4

Перетворення в стилі OOP

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

Крім того, ви можете використовувати вектори, щоб отримати графічний знак *, як показано нижче;

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

3

Ви можете зробити це за допомогою ітератора.

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

Удачі.


3

Безпечна версія char * відповіді orlp за допомогою унікального_ptr:

std::string str = "string";
auto cstr = std::make_unique<char[]>(str.length() + 1);
strcpy(cstr.get(), str.c_str());

3

Для отримання a const char *з std::stringвикористання використовуйте функцію- c_str()член:

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

Щоб отримати non-const char *від an, std::stringви можете використовувати функцію data()member, яка повертає покажчик non-const з 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

Це також спрацює

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;  
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.