Как освободить символ *, который возвращается из другой функции?
Допустим, у нас есть следующий сценарий.
char* halfString(char* input) {
char* output = malloc(strlen(input));
int i = 0;
for(i = 0; i < strlen(input); i++)
output[i] == input[i];
output[i] = '\0';
return output;
}
int main() {
char* input = "Hello";
char* output = halfString(input);
printf("%s\n",output);
free(output);
}
Будет ли вызов "free(output)" освободить память вывода char*, который является локальным для main, и освободит память вывода char*, локального для halfString()? ИЛИ все еще существует утечка памяти для вывода char*, локального для halfString()?
Любая помощь приветствуется.
6 ответов
Нет утечки памяти.
Вы, похоже, не понимаете, как работает распределение кучи. Здесь выделяется только один кусок памяти, и он не является "локальным" для halfString()
или main()
, Выделенный фрагмент существует в куче и не ограничен конкретным блоком кода.
malloc()
возвращает указатель на него. Затем вы возвращаете этот указатель обратно main()
, но значение указателя остается тем же: он указывает на тот же адрес в памяти, тот же кусок кучи. main()
тогда должным образом освобождает это.
В качестве конструктивного решения это часто не самая лучшая вещь. В общем, вызывающая сторона может не обязательно знать, что указатель, возвращаемый halfString()
указывает на кусок, который был выделен с malloc()
и что им нужно free()
Это. Это должно быть очень четко и тщательно задокументировано. Лучшим решением может быть предоставление freeHalfString()
функция, которая делает освобождение; затем, с точки зрения обслуживания, эти две функции могут быть помещены в одно и то же место и поддерживаться одновременно, так что вызывающей стороне не нужно беспокоиться о том, как был выделен буфер или как его освободить.
(Как уже отмечали другие, у вас также есть переполнение буфера, потому что вам нужно выделить strlen(input) + 1
байтов, чтобы включить NULL терминатор.)
Код в основном правильный, потому что malloc()
кладет память на кучу и free()
освобождает это. Неважно, из каких функций они вызваны.
Тем не менее, есть важная ошибка:
char* output = malloc(strlen(input) + 1); // Don't forget +1
strlen()
Функция возвращает количество символов в строке, не считая терминатора.
Эти ошибки могут часто обнаруживаться автоматически при использовании определенных инструментов, таких как Mudflap (компилировать с -fmudflap
, если используется GCC) и Valgrind.
Алгоритмическая сложность
Существует проблема с алгоритмической сложностью вашего кода, которая, вероятно, исчезнет с хорошими компиляторами, когда оптимизация включена.
for(i = 0; i < strlen(input); i++)
Это позвонит strlen()
, который является O(N), и он будет вызывать strlen()
O (N) раз, давая O (N2) асимптотику. Мы можем сделать лучше, вот два исправления:
// Version 1
size_t i, n = strlen(input);
for (i = 0; i < n; i++)
...
// Version 2
size_t i;
for (i = 0; input[i] != '\0'; i++)
...
Вы, кажется, путаете два связанных элемента: буферы и указатели. Буфер - это блок памяти, который в контексте вашего вопроса выделяется с помощью malloc()
, Указатель связан с тем, что он указывает на буфер, но это не сам буфер.
В вашем halfString()
Функция, вы выделяете буфер, и вы храните адрес (указатель на) этого буфера в вашем локальном output
. Затем вы возвращаете его вызывающей стороне, main()
, который по совпадению имеет переменную с тем же именем, которая будет указывать на тот же буфер.
Сейчас в main()
, когда ты free(output);
вы не освобождаете указатель, вы освобождаете буфер, на который указывает указатель. Неважно, где был выделен буфер, важно только то, что буфер был выделен (и еще не освобожден). После этого вызовите ваши основные функции output
переменная все еще существует, и у нее все еще есть адрес того, что когда-то было действительным буфером, но этот буфер, конечно, не должен использоваться, так как он больше не действителен.
Теперь по вашему вопросу "Есть ли утечка памяти?" - Вы использовали malloc для одного буфера, затем вы освободили тот же самый буфер, поэтому нет ссылки. Всегда правильно соединяйте маллок со свободным, и вы будете в хорошей форме.
free()
освободит память, выделенную в самой вызываемой функции. это не локально для любой функции, потому что malloc allocates memory on heap
,
что ты называешь как local memory
находится на stack
это будет освобождено, когда функция вернется.
Так что распределение сделано с помощью malloc
находится на heap
и используемая процедура освободит память, выделенную в вызываемой функции.
Нет утечки памяти. Система знает, сколько памяти связано с указателем, и, поскольку вы не можете освободить часть блока памяти, выделенную с помощью malloc, она освободит все.
Этот код будет работать правильно (если исправлена ошибка, о которой упоминали другие). Звонок в main
освободит память, выделенную в halfString
,
Нет "памяти вывода, которая является локальной по отношению к основной". Что является локальным по отношению к основному, так это выходной указатель, который был размещен в стеке и выйдет из области видимости при выходе из основного режима.