Glibc Corrupted Double Linked List

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

struct paragraph
{
   char** lines;
   int numLines;
};

struct chapter
{
   struct paragraph** paragraphs;
   int numParagraphs;
};

struct book
{
   struct chapter** chapters;
   int numChapters;
};

Вот оскорбительный фрагмент кода, в частности операторы realloc():

//int numChapters = -1;
//char**** book = (void*)0;
struct book* books = malloc(sizeof(struct book*));
books->chapters = malloc(sizeof(struct chapter));

books->numChapters = -1;

//char*** nextChapter;
struct chapter* nextChapter = malloc(sizeof(struct chapter));


while ( (nextChapter = readChapter(bookFile))->paragraphs[0] )
{
    if (++(books->numChapters) > 0)
    {
        books = realloc(books, sizeof(struct chapter*)*books->numChapters);
        books->chapters[books->numChapters - 1] = nextChapter;

    }
}
books = realloc(books, sizeof(struct chapter*)*books->numChapters);
books->chapters[books->numChapters] = (void*)0;

return books;

Функции, вызываемые в этом фрагменте кода, должны работать корректно, по крайней мере, я рассчитываю на этот факт. Это должно быть проблема с неправильным управлением памятью. Спасибо за любой совет!

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


person user2893045    schedule 21.11.2013    source источник
comment
На самом деле, я не вижу, где находится какой-либо [двойной]связный список..   -  person user2864740    schedule 21.11.2013
comment
Эта ошибка возникает при выполнении realloc в операторе if. Кажется, что ему не хватает памяти или что-то в этом роде после того, как он прочитает первые несколько глав. Интересное замечание, однако, что удаление этого оператора realloc полностью позволяет моей программе читать весь файл book.txt, но он не сохраняет все должным образом... вообще.   -  person user2893045    schedule 21.11.2013
comment
Структуры управления памятью повреждены перед вызовом realloc(). Запустите программу под valgrind.   -  person ninjalj    schedule 21.11.2013


Ответы (1)


Может быть, вам не нужны двойные указатели в каждой структуре? У вас есть массивы для глав, для абзацев — не нужно дважды использовать указатели.

Предоставленный код, скорее всего, будет использовать массивы, а не списки. Итак, если вы пытаетесь использовать списки - я упомянул их в конце ответа. В противном случае это проще исправить, чтобы использовать массивы, и вот первая проблема:

if (++(books->numChapters) > 0)
{
    /* here books are reallocated */
    books = realloc(books, sizeof(struct chapter*)*books->numChapters);
    /* but here chapters which had not been reallocated are acessed */
    books->chapters[books->numChapters - 1] = nextChapter;

}

Если у вас есть новая глава, то зачем вам перераспределять книги? Просто перераспределите книги->главы:

if (++(books->numChapters) > 0)
{
    books->chapters = realloc(books->chapters, sizeof(struct chapter*)*books->numChapters);
    books->chapters[books->numChapters - 1] = nextChapter;

}

И в итоге тот же вопрос:

/* books are reallocated, size is bad - reallocated to size of numChapters * (pointer size) */
books = realloc(books, sizeof(struct chapter*)*books->numChapters);
/* perhaps access to non-allocated memory here */
books->chapters[books->numChapters] = (void*)0;

Должно быть:

books->chapters = realloc(books->chapters, sizeof(struct chapter)*books->numChapters);
// books->chapters[books->numChapters] = (void*)0;

Присвоение NULL последнему элементу не требуется, потому что главы имеют размер numChapters, а обращение к элементу numChapters приводит к доступу к нераспределенной памяти, аварийному завершению.

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

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

struct paragraph
{
   struct paragraph *next; // <<-- this field is used to build
                           //      linked list of paragraphs
   char* lines;
   int numLines;
};

struct chapter
{
   struct chapter *next; // <<-- this field is used to build 
                         //      linked list of chapters
   struct paragraph* paragraphs;
   int numParagraphs;
};

struct book
{
   struct chapter* chapters;
   int numChapters;
};

Конечно, требуются соответствующие выделения и назначение указателей «следующие».

person Michael    schedule 21.11.2013