#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]
.