#c #c 11 #c-strings
#c #строка
Вопрос:
У меня есть функция, которая возвращает строку. Однако, когда я вызываю его и делаю c_str()
над ним, чтобы преобразовать в const char*
, это работает только тогда, когда я сначала сохраняю его в другую строку. Если я напрямую вызываю c_str()
функцию, она сохраняет значение мусора в const char*
.
Почему это происходит? Чувствую, что я упускаю здесь что-то очень фундаментальное…
string str = SomeFunction();
const char* strConverted = str.c_str(); // strConverted stores the value of the string properly
const char* charArray= SomeFunction().c_str(); // charArray stores garbage value
static string SomeFunction()
{
string str;
// does some string stuff
return str;
}
Комментарии:
1. c_str() возвращает указатель на базовый массив символов. Проблема в том, что вы вызываете это временно. Итак, после
;
объект удаляется, и вуаля: вы получаете мусор.2. Некоторая информация о том, «как» это не работает, помогла бы.. Ошибки компилятора? Данные мусора? много потенциальных ошибок только в этом фрагменте.
3. В @Yeraze OP четко указано, что в нем хранится значение мусора, поэтому это определенно не ошибка компилятора.
Ответ №1:
SomeFunction().c_str()
дает вам указатель на временную (автоматическую переменную str
в теле SomeFunction
). В отличие от ссылок, время жизни временных объектов в этом случае не увеличивается, и в итоге вы charArray
получаете висячий указатель, объясняющий значение мусора, которое вы увидите позже, когда попытаетесь использовать charArray
.
С другой стороны, когда вы делаете
string str_copy = SomeFunction();
str_copy
является копией возвращаемого значения SomeFunction()
. Вызов c_str()
этой функции теперь дает вам указатель на действительные данные.
Комментарии:
1. Nowdays
str_copy
на самом деле просто переместил владение, но точка все еще действительна.
Ответ №2:
Объект value, возвращаемый функцией, является временным. Результаты c_str()
действительны только в течение срока службы временного. Срок службы временного в большинстве случаев равен концу полного выражения, которое часто является точкой с запятой.
const char *p = SomeFunction();
printf("%sn", p); // p points to invalid memory here.
Обходной путь заключается в том, чтобы убедиться, что вы используете результат c_str()
до окончания полного выражения.
#include <cstring>
char *strdup(const char *src_str) noexcept {
char *new_str = new char[std::strlen(src_str) 1];
std::strcpy(new_str, src_str);
return new_str;
}
const char *p = strdup(SomeFunction.c_str());
Обратите внимание, что strdup
это функция POSIX, поэтому, если вы являетесь платформой, поддерживающей POSIX, она уже есть.
Ответ №3:
-
«
string str
» в методеSomeFunction()
является локальной переменной вSomeFunction()
и сохраняется только внутри областиSomeFunction()
; -
Поскольку возвращаемый тип метода
SomeFunction()
— string, а не ссылка на string, после «return str;
«,SomeFunction()
вернет копию значенияstr
, которое будет сохранено как временное значение в некотором месте памяти, после вызоваSomeFunction()
временное значение будет немедленно уничтожено; -
«
string str = SomeFunction();
» сохранит возвращенное временное значениеSomeFunction()
в stringstr
, фактически является копией этого значения и хранится вstr
, выделяется новый блок памяти, а время жизниstr
больше, чем возвращенное временное значениеSomeFunction()
, после «;
» вызовSomeFunction()
завершен, и возвращенное временное значение немедленно уничтожается, память перерабатывается системой, но копия этого значения все еще хранится вstr
. Вот почему «const char* strConverted = str.c_str();
» может получить правильное значение, фактическиc_str()
возвращая указатель на начальный элементstr
(адрес памяти первого элементаstr
указанного строкового значения), а не возвращаемое временное значениеSomeFunction()
; -
«
const char* charArray= SomeFunction().c_str();
» отличается, «SomeFunction().c_str()
» вернет указатель на начальный элемент возвращаемого временного значения (адрес памяти первого элемента возвращаемого временного строкового значения), но после вызоваSomeFunction()
возвращаемое временное значение уничтожается, и этот адрес памяти повторно используется системой,charArray
может получить значение этого адреса памяти, но не то значение, которое вы ожидали;
Ответ №4:
Используйте strcpy для копирования строки в локально определенный массив, и ваш код будет работать нормально.
Комментарии:
1. В любом случае
SomeFunction().c_str()
выдаст вам недопустимый адрес. Если вы попытаетесьstrcpy
это сделать, это приведет к неопределенному поведению.2. Нет. Сделал это сегодня. Отлично сработало.
3. Не могли бы вы предоставить небольшой, но полный рабочий пример, демонстрирующий это поведение?
4. Это существенно отличается. Проблема в том, что
c_str()
вызывается в результате вызова функции. Это делает недействительным внутреннийchar
указатель, которыйc_str()
выдает вам, потому чтоstring
объект, который является локальным для вызываемой вами функции, вышел из области видимости. Он также не был скопирован, как если бы у вас было что-то вродеstring a = SomeFunction(); ... a.c_str();
. Этого не происходит в коде, на который ссылается, потому чтоc_str()
не вызывается напрямую в результате вызова функции.5. Я чувствую, что вы не очень ясно объяснили это. Пример действительно прошел бы долгий путь. На самом деле, я все еще не до конца уверен, имеете ли вы в виду что-то вроде
char* str = new char[...length goes here...]; strcpy(str, SomeFunction().c_str());
.