2015-11-26 6 views
1

Ниже у меня есть функция trim(). Который удаляет ведущие нули из массива int. Он возвращает указатель, который он получает от malloc(). При запуске цикла последовательных вызовов trim() и free(). Я заметил, что значение, возвращаемое trim() - которое было получено malloc(), на каждой итерации одинаково.Странное двойное свободное поведение

Это мое понимание того, что освободив тот же указатель дважды, если это не NULL, приведет к двойной свободной ошибки. Почему в этой ситуации не встречается ошибка double?

#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    int i, j, length; 
    int n[] = { 4, 5, 6 }; 
    int m[] = { 0, 3, 5 }; 
    int *num; 
    int *trimmed, *trimmed_length; 

    trimmed_length = &length; 

    for (i = 0; i < 10; i++) 
    { 
     num = (i % 2 == 0) ? n : m; 

     trimmed = trim(num, 3, trimmed_length); 

     if (!trimmed) 
     { 
      printf("trimmed was null\n"); 
      exit(-1); 
     } 

     for (j = 0; j < *trimmed_length; j++) 
     { 
      printf("%d", trimmed[j]); 
     } 

     printf("\n"); 

     free(trimmed); 
    } 

    exit(0); 
} 

int *trim(int *n, int nlength, int *res_length) 
{ 
    int i, j; 
    int *res; 

    for (i = 0; i < nlength; i++) 
    { 
     if (n[i] > 0) 
     { 
      break; 
     } 
    } 

    *res_length = (nlength - i); 

    res = malloc(sizeof(int) * (*res_length)); 

    if (!res) 
    { 
     return NULL; 
    } 

    j = 0; 

    while (i < nlength) 
    { 
     res[j++] = n[i++]; 
    } 

    printf("Returned pointer from trim() %d\n", res); 

    return res; 
} 

Выход:

Returned pointer from trim() 11759632 
456 
Returned pointer from trim() 11759632 
35 
Returned pointer from trim() 11759632 
456 
Returned pointer from trim() 11759632 
35 
Returned pointer from trim() 11759632 
456 
Returned pointer from trim() 11759632 
35 
Returned pointer from trim() 11759632 
456 
Returned pointer from trim() 11759632 
35 
Returned pointer from trim() 11759632 
456 
Returned pointer from trim() 11759632 
35 
+3

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

+0

Предоставлено. Теперь у меня вопрос: почему 'trim()' возвращает одно и то же значение при одинаковых вызовах? Например, если мне нужно обрезать список чисел, чтобы предотвратить утечку памяти, мне нужно было бы «освободить» результат 'trim()' перед последующими вызовами. В этом случае, хотя последующие вызовы, похоже, возвращают одно и то же значение, из 'malloc()'. Должно ли 'malloc()' не возвращать новое значение для каждого последующего вызова 'trim()'? – cryptic

+0

Вы выделяете, вы бесплатно. В вашем коде нет ошибки - по крайней мере, не тот, на который вы ссылаетесь. И почему бы вам не использовать одно и то же ведро снова, как только вы его опустошили? Одноразовая память? – Olaf

ответ

2

То, что вы видите, это не двойной бесплатно. Рассмотрим:

void *p1, *p2; 

p1 = malloc(10); 
free(p1); 
p2 = malloc(10); 

На данный момент нет гарантии, что p1 и p2 будут одинаковыми. Нет никакой гарантии, что они разные. Если они окажутся одинаковыми, то вызов free(p2) на данный момент составляет не a double free. Ниже будет фактическое двойной бесплатно:

void *p = malloc(10); 
free(p); 
free(p); 
+0

Это то, что я изначально думал. На самом деле это часть других вопросов, которые я опубликовал: * Malloc возвращает такое же значение - без двойной свободной ошибки *. Я считаю, что мой код следует той же самой парадигме в этом вопросе, но двойная свободная ошибка встречается. Я буду отмечать этот ответ как правильный, как есть. – cryptic

1

Насколько я могу видеть, нет двойной свободный() в вашем случае.

Во-первых, вы выделяете память, используя malloc(), а затем вы free(). После того, как блок памяти был свободен-d, он может быть перераспределен (т. Е. Тот же самый указатель может быть возвращен), используя следующий вызов malloc(). Это совершенно законно (и необходимо), чтобы освободить это.

Если мы внимательно посмотрим на C11 спецификации, глава §7.22.3.3, он говорит (курсив мой)

free функция заставляет пространство указывает ptr быть высвобождены, то есть, изготовлено доступно для дальнейшего размещения. Если ptr является нулевым указателем, никаких действий не происходит. В противном случае, если аргумент не соответствует указателю, ранее возвращенному функцией управления памятью , или если пространство было освобождено вызовом free или realloc, поведение не определено.

Так,

  1. После освобождения, пространство памяти (заточенным Y указатель) может быть перераспределена.
  2. Если указатель не только предварительно освобожденного вызовом free(), это совершенно законно называть free() на указатель, возвращаемый malloc() и семейство функций.