Недопустимый свободный или поврежденный выход

#c #memory-management #free

#c #управление памятью #Бесплатно

Вопрос:

Я новичок в C и полностью сбит с толку этой проблемой. Это домашнее задание для реализации чего-то вроде алгоритма pagerank в C.

Я пытаюсь записать ссылки с других страниц с помощью 2D-массива указатель-указатель. Моя программа работает просто отлично и успешно вычисляет pagerank для больших наборов ссылок, однако всякий раз, когда я пытаюсь освободить свой массив ссылок, я получаю ошибку «недопустимо свободный».

пример кода:

 struct webpage {
  char name[20];
  int links_out;
  struct webpage **links_in; //to hold pointers to pages.
  int index; //stores the position in the pre-sorted array
             // as I have to print it out in this order
};

static struct webpage *pages = NULL;
  

Это моя структура данных. После чтения некоторых базовых переменных, таких как количество страниц (npages) Затем я выделяю память

 pages = (struct webpage *)calloc(npages, sizeof(struct webpage));
  

Когда я читаю на каждой веб-странице, я выделяю внутренний 2d-массив links_in следующим образом

 pages[counter].links_in = (struct webpage **)calloc(npages, sizeof(struct webpage *));
  

и затем каждая страница внутри:

 for(i =0; i< npages;   i)
pages[counter].link_in[i] = (struct webpage *)calloc(1, sizeof(struct webpage));
  

Я сортирую свой массив веб-страниц. Затем прочитайте информацию о ссылке и выполните двоичный поиск в моем массиве с помощью bsearch, чтобы получить указатель на каждую нужную страницу.

 struct webpage *temp_in;
struct webpage *temp_out;

temp_in = bsearch(temp_str, pages, npages, sizeof(struct webpage), struct_cmp_by_name);
temp_out = bsearch(temp_str2, pages, npages, sizeof(struct webpage), struct_cmp_by_name);
  

Затем я назначаю

 temp_in->links_in[temp_out->index] = temp_out;
  

Все это отлично работает, и я могу получить доступ ко всем необходимым данным для вычисления pagerank.
Как только я закончу, я попытаюсь освободить память следующим образом:

 for(int i = 0; i < npages;   i){
  for(int k = 0; k < npages;   k){
     if(pages[i].links_in[k] != NULL){
          free(pages[i].links_in[k]); //this line is causing the error
          pages[i].links_in[k] = NULL;
     }
  }
 free(pages[i].links_in);
}
  

Вызов free внутри цикла k выдает ошибку недопустимого освобождения (или двойного вывода с повреждением) при самом первом вызове.

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

valgrind говорит почти то же самое:

 Invalid free() / delete / delete[]
at 0x4A05187: free (vg_replace_malloc.c:325)
by 0x4009C4: memory_dump (pagerank.c: 87)  // this is the line free(pages[i].links_in[k];
by 0x4013F2: seq_check_condition (pagerank.c:355)
by 0x40162F: main (pagerank.c:418)
  

Ни в коем случае я не удаляю / освобождаю эту (или любую другую память tbh) память до этого момента.

спасибо за любые предложения.

Комментарии:

1. это не отвечает на ваш вопрос, но вы отсортировали свой массив?

2. Массив сортируется после считывания всех страниц, но до определения ссылок

3. хорошо, phoxis был правильным. Я не должен был выделять память для внутреннего массива. Мне нужен был calloc только для страниц [i].links_in.

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

Ответ №1:

Я предполагаю, что в этом и есть проблема:

 temp_in->links_in[temp_out->index] = temp_out;
  

Похоже, вы уже выделили память для всех ваших указателей ‘links_in’ — затем вы меняете этот указатель, чтобы он указывал на другой выделенный вами бит памяти.

Может быть, вы хотите что-то вроде:

 memcpy(temp_in->links_in[temp_out->index], temp_out, sizeof(struct webpage));
  

… или небольшой редизайн?

Комментарии:

1. хорошо, это было странно. Я внес это изменение, и я получил ошибку сегмента. размер обеих переменных находится в пределах размера веб-страницы структуры.

2. копирование всей структуры веб-страницы — не очень хорошая идея, я думаю, вместо этого указатель на эту страницу был бы лучше.

Ответ №2:

Я думаю, вам не нужно делать следующее

 for(i =0; i< npages;   i)
    pages[counter].link_in[i] = (struct webpage *)calloc(1, sizeof(struct webpage));
  

Это потому, что для каждой страницы вы выделяете новый webpage указатель. pages[counter].link_in[i] Используется для удержания указателя на webpage , ie. он должен указывать на уже существующую и выделенную страницу. Таким образом, вам нужно назначить адрес только этого webpage экземпляра.

Я думаю, что проблема здесь:

Измените этот код:

 for(int i = 0; i < npages;   i){
  for(int k = 0; k < npages;   k){
     if(pages[i].links_in[k] != NULL){
          free(pages[i].links_in[k]); //this line is causing the error
          pages[i].links_in[k] = NULL;
     }
  }
 free(pages[i].links_in);
}
  

К этому:

 for(int i = 0; i < npages;   i){
   free (pages[i].links_in);
}
free (pages);
  

Это потому, что pages[i].links_in[x] удерживаемые ссылки являются указателями на некоторые pages[j] , и потому, что конкретный pages[j] адрес может встречаться в pages[i].links_in[x] для любого числа i , так что потенциально адрес pages[j] встречается в нескольких местах, которые пытается освободить ваша подпрограмма в строке free(pages[i].links_in[k]); .

Пожалуйста, дайте нам знать, если это поможет.

Комментарии:

1. ЕСЛИ я изменю свой код в соответствии со второй частью вашего ответа, ошибка исчезнет, но память, выделенная для ссылки [k], будет потеряна. Я попробую внести первое предложенное вами изменение.

2. утечки памяти быть не должно, при условии, что вы также будете следовать первой части моего ответа, не выделяя webpage структуры. Это связано с тем, что вы используете link_in для указания на существующую ячейку памяти, и для этого вам не нужно выделять новую копию памяти. Вместо этого выполнение calloc (которое я выделил в своем ответе) приведет к утечке памяти. Я бы предложил провести дальнейшее исследование вашего кода.

Ответ №3:

Похоже, pages[i].links_in[k] так и должно быть pages[i].link_in[k] .