2016-09-25 3 views
0

Я хочу понять поведение возврата указателя из вызова функции. Предположим, у меня есть следующий простой код:Понимание free() буфера перед оператором return

int main(){ 
    int i; 
    float *ssd; 
    ssd = test(); 

    for (i = 0; i < 3; ++i) { 
     printf("%f, ", ssd[i]); 
    } 
    printf("\n \n"); 

    memset(ssd, 0.0, 3*sizeof(float)); 

    for (i = 0; i < 3; ++i) { 
     printf("%f, ", ssd[i]); 
    } 
    printf("\n \n"); 

} 

float *test(){ 

    float *buff = malloc(3* sizeof(float)); 
    int i; 
    for (i = 0; i < 3; ++i) { 
     buff[i] = (float) (6.31 + i); 
    } 

    free(buff); 
    return buff; 

} 

Как вы видите, я создал временный буфер buff внутри test(). Прежде чем я вернусь, я освободил buff перед заявлением return. Хотя я протестировал его, и результаты были такими, как ожидалось, я не понимаю, как функция test() может вернуть значения buff, хотя free(buff) есть до return buff?

+0

Похожие: http://stackoverflow.com/q/6441218/509868 – anatolyg

+2

нет ничего невозможного в программе C с неопределенным поведением. – PSkocik

+2

это неправильный код. Это приведет к коррупции. Кажется, что использование после бесплатной ошибки –

ответ

5

После

free(buff); 

любые дальнейшие операции, которые являются разыменовать buffнеопределенное поведение.

test() Ваша функция выделяет буфер, а затем free оно что перед возвращением его в main как ssd.

Так что, когда ssd разыменовывается в main, хотя указатель все еще имеет то же значение, что было выделено на malloc, он уже не указывает на память, что вы «владеете». Поэтому с этого момента все может случиться. Ваш код может по-прежнему работать, а может и нет.

+0

Благодарим вас за это объяснение. В этом случае, пожалуйста, не могли бы вы объяснить, как лучше всего изменить этот случай, чтобы избежать двусмысленности? Помещение 'free()' после выражения 'return' не будет работать точно, поэтому я не знаю, что делать дальше! – Adam

+0

Вы можете только «освободить» память * после *, которую вы сделали, используя свой контент. Пока значение 'ssd' в' main' не было изменено, вы можете 'free (ssd)' в 'main', если вы больше не используете его, поскольку оно все еще имеет такое же значение указателя, как' buff = malloc (3 * sizeof (float)) 'в функции. –

+0

@Adam Если вы хотите узнать «как исправить свой код», а не «что не так», задайте отдельный вопрос. Возможно, вы захотите вернуть массив (используя методы, описанные здесь (http://stackoverflow.com/q/11656532/509868) или [здесь] (http://stackoverflow.com/q/8617889/509868)) из вашей функции, а не использовать 'malloc' и' free' вообще. – anatolyg

0

Память, указанная первоначально buff, не перезаписывается, сохраняя при этом сохраненные в ней значения.

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

0

От LibC документации,

Иногда, бесплатно фактически может вернуть память операционной системы и сделать процесс меньше. Как правило, все, что он может сделать, это разрешить более поздний вызов в malloc для повторного использования пробела. Между тем, пространство остается в вашей программе как часть бесплатного списка, используемого внутри malloc.

Звонок на бесплатный не гарантирует, что пространство очищено. Но то, что гарантировано (по крайней мере, реализацией GNU libc), заключается в том, что

  1. Освобожденное таким образом пространство, возможно, будет использоваться средой выполнения в будущих вызовах любых динамических программ распределения памяти.

Чтобы доказать это, я изменил вашу программу следующим образом. Он в основном добавляет цикл for в вашу функцию test(), которая просто выделяет и освобождает бафф за n раз (например, 10 раз) и печатает содержимое буфера в курсе. Поэтому каждый раз, когда я запускаю программу, он печатает содержимое в первый раз и когда malloc() и free() вызывается, содержимое * buff очищается, а мусор печатается. (тестируется на mac, gcc 4.8+). Надеюсь, это поможет.

#include<stdlib.h> 
 
#include<stdio.h> 
 
#include<string.h> 
 
float *test(){ 
 
    float *buff = malloc(3* sizeof(float)); 
 
    int i, j; 
 
    for (i = 0; i < 3; ++i) { 
 
    buff[i] = (float) (6.31 + i); 
 
    } 
 
    free(buff); 
 
    int n = 10; 
 
    for(i=0;i<n;i++) 
 
    { 
 
    printf("Iteration %d ", i); 
 
    for (j = 0; j < 3; ++j) { 
 
     printf("%f, ", buff[i]); 
 
    }  
 
    printf("\n"); 
 
    buff = malloc(3 * sizeof(float)); 
 
    free(buff); 
 
    } 
 
    return buff; 
 

 
} 
 
int main(){ 
 
    int i; 
 
    float *ssd; 
 
    ssd = test(); 
 
    printf("\n \n"); 
 
    memset(ssd, 0.0, 3*sizeof(float)); 
 
    for (i = 0; i < 3; ++i) { 
 
    printf("%f, ", ssd[i]); 
 
    } 
 
    printf("\n \n"); 
 
}

Смежные вопросы