Возврат указателя на автоматическую переменную - PullRequest
10 голосов
/ 03 августа 2009

Скажем, у вас есть следующая функция:

char *getp()
{
    char s[] = "hello";
    return s;
}

Поскольку функция возвращает указатель на локальную переменную в функции, которая будет использоваться снаружи, это вызовет утечку памяти?

P.S. Я все еще изучаю C, поэтому мой вопрос может быть немного наивным ...

[Update]
Итак, если, скажем, вы хотите вернуть новый массив char[] (то есть, может быть, для функции подстроки), что именно вы вернете? Должен ли он быть указателем на внешнюю переменную? то есть char[], который не является локальным для функции?

Ответы [ 8 ]

25 голосов
/ 03 августа 2009

Это не приведет к утечке памяти. Это приведет к зависанию. Локальная переменная размещается в стеке и будет освобождена, как только она выйдет из области видимости. В результате, когда функция завершается, указатель, который вы возвращаете, больше не указывает на вашу память. Это не утечка памяти (утечка памяти - это когда вы выделяете память и не освобождаете ее).

[Update] : Чтобы иметь возможность возвращать массив, выделенный в функции, вы должны выделить его вне стека (например, в куче), например:

char *test() {
    char* arr = malloc(100);
    arr[0] = 'M';
    return arr;
}

Теперь, если вы не free памяти в вызывающей функции после того, как вы закончили ее использовать, у вас будет утечка памяти.

13 голосов
/ 03 августа 2009

Нет, он не протечет, так как уничтожается после завершения getp ();

Это приведет к неопределенному поведению, потому что теперь у вас есть указатель на область памяти, которая больше не содержит того, что вы думаете, и может быть использована любым другим.

Утечка памяти произошла бы, если бы вы сохранили этот массив в куче, не выполняя вызов free ().

char* getp(){

   char* p = malloc(N);
   //do stuff to p
   return p;
}

int main(){
    char* p = getp();
    //free(p) No leak if this line is uncommented
    return 0;
}

Здесь p не уничтожается, потому что он не в стеке, а в куче. Однако после завершения программы выделенная память не освобождается, что приводит к утечке памяти (даже если это происходит после завершения процесса).

[UPDATE]

Если вы хотите вернуть новую c-строку из функции, у вас есть две опции.

  • Храните его в куче (как пример выше или как этот реальный пример , который возвращает дублированную строку);
  • Передать параметр буфера

например:

    //doesnt exactly answer your update question, but probably a better idea.
    size_t foo (const char* str, size_t strleng, char* newstr);

Здесь вам нужно было бы выделить место где-нибудь для newstr (это может быть стек или куча) перед вызовом функции foo. В этом конкретном случае будет возвращено количество символов в newstr.

8 голосов
/ 03 августа 2009

Это не утечка памяти, потому что память освобождается должным образом.

Но это ошибка. У вас есть указатель на нераспределенную память. Он называется свисающая ссылка и является распространенным источником ошибок в C. Результаты не определены. Вы не увидите никаких проблем до времени выполнения, когда попытаетесь использовать этот указатель.

3 голосов
/ 03 августа 2009

Автоматические переменные уничтожаются в конце вызова функции; вы не можете вернуть указатель на них. То, что вы делаете, можно описать как «возвращение указателя на блок памяти, который раньше содержал s, но теперь не используется (но может все еще иметь что-то в нем, по крайней мере, на данный момент), и это будет быстро заполнено чем-то остальное целиком. "

2 голосов
/ 04 августа 2009

Никто другой не упомянул еще один способ сделать эту конструкцию допустимой: скажите компилятору, что вы хотите, чтобы массив "s" имел "статическую продолжительность хранения" (это означает, что он живет в течение жизни программы, как глобальная переменная). Вы делаете это с ключевым словом "static":

char *getp()
{
    static char s[] = "hello";
    return s;
}

Теперь недостатком этого является то, что теперь существует только один экземпляр s, совместно используемый каждым вызовом функции getp (). С функцией, как вы ее написали, это не будет иметь значения. В более сложных случаях он может не выполнять то, что вы хотите.

PS: Обычный вид локальных переменных имеет так называемую «продолжительность автоматического хранения», что означает, что новый экземпляр переменной создается при вызове функции и исчезает при ее возврате. Есть соответствующее ключевое слово "auto", но оно все равно подразумевается, если вы не используете "static", поэтому вы почти никогда не увидите его в реальном коде.

2 голосов
/ 03 августа 2009

Это не приведет к утечке памяти, но приведет к неопределенному поведению. Этот случай особенно опасен, потому что указатель будет указывать где-то в стеке программы, и если вы используете его, вы будете получать доступ к случайным данным. Такой указатель при записи может также использоваться для нарушения безопасности программы и выполнения произвольного кода.

1 голос
/ 03 августа 2009

Я удалил свой предыдущий ответ после помещения кода в отладчик и наблюдения за разборкой и окном памяти.

Код в вопросе недействителен и возвращает ссылку на стековую память, которая будет перезаписана.

Эта немного другая версия, однако, возвращает ссылку на фиксированную память и работает нормально:

char *getp()
{
    char* s = "hello";
    return s;
}
0 голосов
/ 03 августа 2009

s - переменная стека - она ​​автоматически отменяется в конце функции. Однако ваш указатель будет недействительным и будет указывать на область памяти, которая может быть перезаписана в любой момент.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...