перетворити char * в std :: string


262

Мені потрібно використовувати std::stringдані для зберігання даних, отриманих користувачем fgets(). Для цього мені потрібно перетворити char*повернене значення з fgets()в std::stringна зберігання в масиві. Як це можна зробити?

Відповіді:


376

std::string має конструктор для цього:

const char *s = "Hello, World!";
std::string str(s);

Зауважте, що ця конструкція глибоко копіює список символів у sі sне має бути nullptr, інакше поведінка не визначена.


6
що буде, якщо це буде?
Карсон Майєрс

14
Стандарт говорить, що параметр конструктора "не повинен бути нульовим покажчиком" - він не вказує, що викидаються будь-які винятки.

24
Це неглибока чи глибока копія?

4
@pushkin Ні str- це не лише ім'я змінної. Це може бути що завгодно: S, abc, l, I, strHelloWorld. Очевидно, деякі варіанти кращі за інші. Але для цього приклад strцілком прийнятний.
Розчарований

10
@Madhatter це глибока копія. Виділення вказівника залишиться, і рядок зробить собі нове виділення.
moodboom

127

Якщо ви вже знаєте розмір знака *, використовуйте це замість цього

char* data = ...;
int size = ...;
std::string myString(data, size);

Для цього не використовується strlen.

EDIT: Якщо струнна змінна вже існує, використовуйте призначити ():

std::string myString;
char* data = ...;
int size = ...;
myString.assign(data, size);

1
Добрий питання, Євгеній. Якщо дані не заповнюються до пізніше у рутині, як потім ініціалізувати myString? Ви просто оголошуєте змінну myString, коли вона заповнена?
IcedDante

2
int size = strlen (дані);
Влад

@vlad: ідея полягає в тому, що ви знаєте розмір з якогось іншого джерела та / або дані не є C-рядком (має вбудовані нулі або не закінчується нулем). Якщо у вас є C-рядок, ви можете просто зробити myString = data; він буде запущений strlen або еквівалентний для вас.
Євген

1
@huseyintugrulbuyukisik Вам все-таки потрібно належним чином розпоряджатися оригінальною пам'яттю - std :: string буде копіювати байти, вона не приймає на себе право власності.
Євген

2
@ZackLee він виділить нову пам’ять для байтів і скопіює їх все там, настільки глибоко, як вона стане. Якщо ви хочете отримати потенціал для дрібної копії, вам потрібно скопіювати один рядок std :: в інший. Тоді деякі реалізації можуть зробити дрібну копію, я думаю.
Євген

30

Більшість відповідей говорить про побудову std::string .

Якщо це вже побудовано, просто скористайтеся оператором призначення .

std::string oString;
char* pStr;

... // Here allocate and get character string (e.g. using fgets as you mentioned)

oString = pStr; // This is it! It copies contents from pStr to oString

28

Мені потрібно використовувати std :: string для зберігання даних, отриманих fgets ().

Навіщо використовувати, fgets()коли ви програмуєте C ++? Чому ні std::getline()?


18

Передайте його через конструктор:

const char* dat = "my string!";
std::string my_string( dat );

Ви можете скористатися функцією string.c_str (), щоб перейти іншим шляхом:

std::string my_string("testing!");
const char* dat = my_string.c_str();

3
c_str()повертаєтьсяconst char*
Стів Джессоп

1
правильно, ви не можете (не повинні) змінювати дані в рядку std :: через c_str (). Якщо ви маєте намір змінити дані, то рядок c з c_str () має бути memcpy'd
Carson Myers

11
const char* charPointer = "Hello, World!\n";
std::string strFromChar;
strFromChar.append(charPointer);
std::cout<<strFromChar<<std::endl;


5

Я хотів би згадати новий метод, який використовує визначений користувачем буквал s. Це не нове, але воно буде більш поширеним, оскільки його додано у стандартну бібліотеку C ++ 14.

В основному зайвим у загальному випадку:

string mystring = "your string here"s;

Але це дозволяє використовувати авто, також із широкими рядками:

auto mystring = U"your UTF-32 string here"s;

І ось де воно справді світить:

string suffix;
cin >> suffix;
string mystring = "mystring"s + suffix;

2

Я щойно боровся з MSVC2005, щоб використовувати std::string(char*)конструктор так само, як найкращу відповідь. Оскільки я вважаю, що цей варіант вказаний як №4 у завжди надійному http://en.cppreference.com/w/cpp/string/basic_string/basic_string , я вважаю, що це пропонує навіть старий компілятор.

Мені знадобилося стільки часу, щоб зрозуміти, що цей конструктор абсолютно не хоче відповідати (unsigned char*)аргументом! Я отримав ці незрозумілі повідомлення про помилки щодо невідповідності std::stringтипу типу аргументу, що точно не було те, до чого я прагнув. Лише аргументація std::string((char*)ucharPtr)вирішила мою проблему ... так!


0
char* data;
std::string myString(data);

9
Це призведе до невизначеної поведінки.

1
Тільки ці два рядки dataзалишаються неініціалізованими (порожніми).
heltonbiker

1
Без істинної "довжини" покажчика, цей код може призвести до втрачених даних, ваш std :: string буде "коротшим", ніж оригінальний char *
Andiana

0

Не впевнений, чому ніхто, окрім Еріка, не згадав про це, але згідно з цією сторінкою , оператор присвоєння працює чудово. Не потрібно використовувати конструктор, .assign () або .append ().

std::string mystring;
mystring = "This is a test!";   // Assign C string to std:string directly
std::cout << mystring << '\n';

1
Це, здається, працює функціонально, але коли я це зробив, у кінці програми почали виникати проблеми з доповідними блоками Valgrind, що походять від "нового" всередині =+=). Схоже, це не відбувається з буквами, як це, а просто з char*речами. Питання про те, чи є такі звіти насправді витоками, обговорюється тут . Але якщо я змінив присвоєння destString = std::string(srcCharPtr);вальгриндським звітам про витоки пішов. YMMV.
HostileFork каже, що не довіряйте SE

Коментар HostileFork може привести вас до думки, що побудова рядка з char * (наприклад, з fgets) змусить std :: string керувати життям цієї пам'яті. Однак це не так. Див. Стандарт 21.4.2.7 та .9 Constructs an object of class basic_string and determines its initial string value from the array. Він говорить про значення і нічого про власність буферів або вказівників.
Ерік ван Вельцен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.