Связанный список с бесконечным циклом

Кажется, прямо здесь, в моем коде, у меня есть бесконечный цикл вывода одной и той же переменной class_t, называемой search, несмотря на попытку переместить переменную вперед к следующему class_t. Все структуры class_t либо указывают на (class_t*)0 (потому что я получил предупреждения компилятора, если я использовал NULL, потому что я сравнивал class_t* и void*), либо указывают на следующую подходящую структуру class_t. Что я делаю не так, или мне искать проблему в другом месте?

class_t *search = (students + i)->class_p;//students is a seperate structure where class_p is a pointer to a class_t structure
            while(search != (class_t*)0)
            {
                    fprintf(output,": %s%d %d %d\n", search->name, search->number, search->section, search->credits);
                    search = search->nextClass;
            }

Вот пример вывода, и, глядя на него, это последнее чтение в class_t из файла

: CS521 1 4
: CS521 1 4
: CS521 1 4
: CS521 1 4
: CS521 1 4
: CS521 1 4
: CS521 1 4
: CS521 1 4
: CS521 1 4
: CS521 1 4
: CS521 1 4
: CS521 1 4

А вот создание class_t:

    class_t newClass;
newClass.number = classid;
newClass.section = section;
newClass.credits = credits;
newClass.nextClass = (class_t*)0;

И когда узел добавлен:

void addNode(student_t students[], class_t addClass, int ref)
{
int found = 0;

if((students + ref)->class_p == (class_t*)0)//no classes yet
{
    (students + ref)->class_p = &addClass;
    found = 1;
}
else if((*((students + ref)->class_p)).number > addClass.number && found == 0)//checks first class
{
    class_t *temp = (students + ref)->class_p;
    (students + ref)->class_p = &addClass;
    addClass.nextClass = temp;
    found = 1;
}
else//works way through the class linked list to find where it goes
{
    class_t *beforesearch = (students + ref)->class_p;
    class_t *search = beforesearch->nextClass;
    while(search != (class_t*)0 && found == 0)
    {
        if(search->number < addClass.number)
        {
            beforesearch->nextClass = &addClass;
            addClass.nextClass = search;
            found = 1;
        }
        else
        {
            beforesearch = search;
            search = search->nextClass;
        }
    }

    if(found == 0)
    {
        beforesearch->nextClass = &addClass;
        found = 1;
    }
}

}

Заголовочные файлы с typedefs:

typedef struct class_t {
char name[3];
int number;
int section;
int credits;
struct class_t *nextClass;
} class_t;

typedef struct student_t {
int id;
class_t *class_p;
} student_t;

person Setzra    schedule 19.04.2012    source источник
comment
Я бы оценил, как вы обрабатываете свою голову/хвост при добавлении/удалении узлов. Вероятно, вы вводите цикл.   -  person Thomas    schedule 20.04.2012
comment
Нужно посмотреть, как вы составили список. В нем есть петля!   -  person Ed Heal    schedule 20.04.2012
comment
Пожалуйста, добавьте образец вывода, чтобы мы могли увидеть, есть ли шаблон — если Слакс прав — он, вероятно, будет показан в образце вывода.   -  person amit    schedule 20.04.2012
comment
Какие жалобы вы получили, когда использовали NULL? Жалобы от составителя или от вашего руководителя?   -  person Anthales    schedule 20.04.2012
comment
Вы можете найти Черепаху и Зайца.   -  person pmg    schedule 20.04.2012
comment
в AddNode() вы берете адрес addclass (который является аргументом функции) и назначаете его указателю -›nectClass. ПРИМЕЧАНИЕ. Это не ошибка, но мне кажется, что это неправильно.   -  person wildplasser    schedule 20.04.2012
comment
@wildplasser Изменил его, чтобы использовать указатель на исходную структуру, а не использовать копию в аргументе, получить тот же цикл.   -  person Setzra    schedule 20.04.2012
comment
Как я уже сказал, это не главная ошибка, есть и другие. Также отсутствуют определения типов для student_t и class_t. (и у вас очень странный стиль индексации массива/понтер-разыменования, что затрудняет чтение кода, по крайней мере для меня.)   -  person wildplasser    schedule 20.04.2012
comment
@wildplasser Ссылка на указатель индексации массива является предпочтением профессора, извините. Typedef находится в моих заголовочных файлах, но я добавлю их туда, если вы хотите посмотреть   -  person Setzra    schedule 20.04.2012
comment
Я добавил тег домашнего задания, чтобы удовлетворить оскорбительного профессора. Может быть, ему самому стоит здесь разместить (или у него есть дидактические стратегии)?   -  person wildplasser    schedule 20.04.2012
comment
@wildplasser Я пытаюсь связаться с этим профессором, но он, как правило, довольно часто отсутствует: P И в целом у него не так много стратегий.   -  person Setzra    schedule 20.04.2012
comment
Почему бы вам не напечатать и адрес узла? На всякий случай это не узел, указывающий на себя, а замкнутая цепочка или цикл   -  person C2H5OH    schedule 20.04.2012


Ответы (1)


Это очень тонкая ошибка:

void addNode(student_t students[], class_t addClass, int ref)
{
    int found = 0;

    if((students + ref)->class_p == (class_t*)0)//no classes yet
    {
        (students + ref)->class_p = &addClass;

Вы передаете addClass по значению (т.е. всю копию структуры, которую я полагаю), а затем используете ее адрес, чтобы связать ее в списке. Это неправильно, так как вы используете адрес параметра функции, который принадлежит стеку вызовов.

Если вы получаете цикл списка, это означает, что вы попали в случай, когда каждый вызов addNode копирует структуру по одному и тому же адресу в стеке. Но это большая удача, есть так много вещей, которые могут пойти не так с этим кодом, что я не буду объяснять их все.

Правильное решение — выделить class_t узлов в куче (т. е. с malloc()) и передать на них указатель. Или еще выделить копию перед связыванием:

void addNode(student_t students[], class_t addClass_param, int ref)
{
    class_t *addClass = malloc(sizeof(class_t)); /* Check for NULL return skipped */
    memcpy(addClass, &addClass_param, sizeof(class_t));
    /* ... */
person C2H5OH    schedule 19.04.2012
comment
Я принял ваше предложение, но это ничего не изменило. Я дал ему место в куче, а также убедился, что все было скопировано на новое место. Однако теперь он ничего не печатает в выходной файл и все еще застревает в каком-то цикле. - person Setzra; 20.04.2012
comment
@Setzra: Это та ситуация, когда отладчик пригодится. - person C2H5OH; 20.04.2012