C - LinkedList排序无限循环

时间:2015-05-21 23:36:09

标签: c sorting linked-list

我正在创建一个程序,它将从main.c中的文本文件中读取一个单词,并将其发送到list.c文件以创建一个新节点来存储该单词。该节点还将存储三个整数:第一个(该字出现在txt文件1中的次数),第二个(该字出现在txt文件2中的次数)和dif(绝对(第一秒))。将所有新单词添加到文件并计算每个txt文件中每个单词存在的次数后,main.c将调用一个方法来计算每个节点的第一个和第二个之间的差异。这是差异(以每个节点的dif存储)将用于按递减顺序对链接节点进行排序。

EX。单词:the,first:2888,second:2466,dif:422。           红色,39 12 27           .....

但是,当main调用sort方法时,会发生无限循环。这个无限循环来自排序算法的内部循环,其中当前节点从curr-> next指针分配节点。在排序方法期间的某处,当前节点的下一指针指向当前节点,而不是链表中的实际下一节点。如果排序方法是dactivated,那么所有其他函数都可以正常工作,包括printAll,它遍历整个列表并在每个节点中打印数据(参见上面的例子)。

我的问题是我无法在我的排序方法中找到current-> next开始指向当前节点的位置。任何帮助表示赞赏!

/*
 * list.h
 */

#ifndef LIST_H_
#define LIST_H_

typedef struct node Node;

void findWord(char *word, int book);
void addWord(char *word, int book);
void editWord(Node **endPtr, int book);
void sort();
void swap(Node **a, Node **b);
void calculateDiff();
void printAll();


#endif /* LIST_H_ */




/*
 * list.c
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"

typedef struct node{
    int first;
    int second;
    int dif;
    char name[20];
    struct node *next;
}Node;

Node *front = NULL;

/*
 * Sees if the current word exists in the
 * linkedlist.
 */
void findWord(char *word, int book) {
    Node *curr = front;
    int boolean = 0;

    while (curr != NULL) {
        if(strcmp(curr->name, word) == 0) {
            boolean = 1;
            editWord(&curr, book);
            break;
        }
        curr = curr->next;

    }

    if(!boolean) { //Add word if it does not exist.
        addWord(word, book);
    }
}

/*
 * Creates a new node for the added word. Adds to front.
 */
void addWord(char *word, int book) {
    Node *newNode = malloc (sizeof(Node));

    /*
     * Since this word is being added
     * to the linkedlist with a newly
     * created node, either the
     * first or second int must be to 1
     * while the other is set to 0. Based
     * off of book int.
     */
    if(book == 1) {
        newNode->first = 1;
        newNode->second = 0;
    } else {
        newNode->first = 0;
        newNode->second = 1;
    }

    newNode->dif = 0;
    strcpy(newNode->name, word);

    newNode->next = front;
    front = newNode;

}

/*
 * Edits the data for an existing word.
 * Only called if current word exists in
 * the linkedlist.
 */
void editWord(Node **endPtr, int book) {
    if (book == 1) {
        (*endPtr)->first++;
    } else {
        (*endPtr)->second++;
    }
}

/*
 * Sorts the list in descending order based on
 * difference value.
 */
void sort() {
    Node *curr, *last = NULL;
    curr = front;

    while (curr != last) {
        while (curr->next != last) {
            if(curr->dif < curr->next->dif ) {
                swap(&curr, &curr->next);
            }
            curr = curr->next;
        }
        last = curr;
        curr = front;
    }
}

/*
 * Swaps the data in the current and next node in the list.
 */
void swap(Node **a, Node **b) {
    int temp;
    char nameTemp[20];


    //Swap first
    temp = (*a)->first;
    (*a)->first = (*b)->first;
    (*b)->first = temp;

    //Swap second
    temp = (*a)->second;
    (*a)->second = (*b)->second;
    (*b)->second = temp;

    //Swap dif
    temp = (*a)->dif;
    (*a)->dif = (*b)->dif;
    (*b)->dif = temp;

    //Swap name
    strcpy(nameTemp, (*a)->name);
    strcpy((*a)->name, (*b)->name);
    strcpy((*b)->name, nameTemp);
}

/*
 * Calculates the difference between first and second
 */
void calculateDiff() {
    Node *curr = front;
    while(curr != NULL) {
        curr->dif = abs((curr->first - curr->second));
        curr = curr->next;
    }
}

/*
 * Prints all the data from the nodes.
 */
void printAll() {
    printf("|| Word || RedBadge || LittleRegiment ||  Diff\n");
    Node *curr = front;
    while ( curr != NULL  ) {
        printf("%s, %d, %d, %d\n", curr->name, curr->first, curr->second, curr->dif);
        curr = curr->next;
    }
}

/*
 * main.c
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "list.h"

void readBook(int book, FILE *infile);
void readLine(char *line, int book);

int main (void) {
    setvbuf(stdout, NULL, _IONBF,0);
    FILE *infile = fopen("RedBadge.txt", "r");
    FILE *infile2 = fopen("LittleRegiment.txt", "r");
    readBook(1, infile);
    readBook(2, infile2);
    fclose(infile);
    fclose(infile2);
    calculateDiff(); 
    sort();
    printAll();
    return 0;
}

void readBook(int book, FILE *infile) {
    char line[70];

    //Read in each line
    while (!feof(infile)) {
        fgets(line, 70, infile);
        readLine(line, book);
    }
}

void readLine(char *line, int book) {
    int i = 0, j = 0;
    char word[20];


    while (line[i]) {
        line[i] = tolower(line[i]); //Convert line to lowercase
        if((line[i] <= 'z' && line[i] >= 'a') || line[i] == 39 || line[i] == '-') {
            word[j] = line[i];
            j++;
        } else if (j != 0) {
            word[j] = '\0';
            findWord(word, book);
            j = 0;
        }
        i++;
    }
}

1 个答案:

答案 0 :(得分:1)

我相信你的错误实际上是缓冲区溢出。这些书中的单词长度超过19个字符(最大值适合您的word变量)。当您的readline函数尝试读取这些单词时,它将在word数组的边界之外写入,这是未定义的行为。然后它还会使用strcpy将单词复制到节点中,这也将溢出节点的word数组。

快速解决方法是扔掉超过19的额外字符,这些字符不适合你的单词数组。在readline中添加一个大j大小的测试:

        if (j < sizeof word - 1) {
            word[j] = line[i];
            j++;
        }

其中一个词是&#34; ain&#t; t - 掠夺----&#34; (至少在我下载的文本副本中),这让我想到也许你也应该在标点符号上分词。