Я всегда смущаюсь возвратом строковый литерал или строка от функции. Мне сказали, что могла бы быть утечка памяти, потому что Вы не знаете, когда память будет удалена?
Например, в коде ниже, как реализовать foo()
чтобы сделать вывод кода, "Привет Мир"?
void foo ( ) // you can add parameters here.
{
}
int main ()
{
char *c;
foo ( );
printf ("%s",c);
return 0;
}
Кроме того, если тип возврата foo()
не является пустым, но можно возвратиться char*
, каково это должно быть?
Полагаю, мы не можем изменить main. Чтобы ваша программа работала без утечек, вам нужно иметь статическое хранилище:
void foo(char*& pC) // reference
{
static char theString[] = "thingadongdong";
pC = theString;
}
Но на самом деле это не совсем обычный код C ++. Вы бы использовали std :: string
и std :: cout
, поэтому у вас нет , чтобы беспокоиться о памяти:
std::string foo(void)
{
return "better thingadongdong";
}
int main(void)
{
// memory management is done
std::cout << foo() << std::endl;
}
Если вы ' re интересно, нужно ли что-то освободить вручную, это делается неправильно.
Меня всегда смущает возврат строкового литерала или строки из функции.
Неизменяемая, литеральная строка
Как я понимаю, вы можете безопасно вернуть строковый литерал напрямую, если тип возвращаемого значения объявлен const, чтобы объявить, что строка не предназначена для изменения. Это означает, что вам не нужно беспокоиться о продолжительности жизни утечек строки / памяти.
Изменяемая, не литеральная строка
Однако, если вам нужна строка, которую вы можете изменить на месте, необходимо учитывать срок службы строки и размер выделенной памяти, в которой она хранится. Это становится проблемой, поскольку вы больше не можете беспечно возвращать одну и ту же память, содержащую строку для каждого вызова функции, поскольку предыдущее использование могло изменить содержимое этой памяти и/или все еще может использоваться. Следовательно, для хранения возвращаемой строки должен быть выделен новый фрагмент памяти.
Именно здесь возникает вероятность утечки, и где необходимо сделать выбор о том, где должно происходить распределение и распределение. Вы можете заставить саму функцию выделить память и состояние в документации, что это происходит, и указать в ней, что вызывающий абонент должен освободить память, когда она больше не требуется (предотвращая утечку). Это означает, что функция может просто вернуть символ *.
Другой вариант заключается в передаче некоторой памяти функции, которая была выделена вызывающей стороной, и помещении функции строки в эту память. В этом случае вызывающий абонент выделяет и отвечает за освобождение этой памяти.
Наконец, я упомянул, что размер памяти и строки необходимо управлять при использовании изменяемой строки. Выделение должно быть достаточно большим как для строки, изначально заданной функцией, так и для любых изменений, которые производятся после функции, до освобождения памяти. Если это сделать правильно, это может привести к переполнению буфера путем записи строки в длину, чтобы поместиться в первоначально выделенной памяти; это крайне опасно для здоровья и безопасности вашей программы. Это может привести к ошибкам и дырам в безопасности, которые чрезвычайно трудно обнаружить (поскольку источник ошибки - переполнение - может быть далек от симптомов, наблюдаемых при сбое программы).
Что-то вроде этого:
void foo(char ** pChar)
{
// Make sure the string is shorter
// than the buffer
*pChar = new char[256];
strcpy(*pChar,"Hello World!");
}
Затем вызовите это так:
foo(&c);
Как упоминалось в комментарии, будьте осторожны, чтобы хранимая строка была меньше буфера, иначе вы получите... переполнение стека! (Pun intended)