c-在链表中的另一个节点之前插入一个节点时出现问题



我试图在插入链接列表时按字母顺序排列(从文件中(-我目前有三个检查(我会用它来解释我的逻辑-如果有人有更好的想法,请告诉我,我已经为此烦恼了一整天(:

如果从文件中获取的单词与当前节点中的单词匹配,只需增加节点中的频率计数器即可(无需创建新节点(。如果单词出现在当前节点之前,则将previous->指向新创建的节点旁边,并将new_node->指向当前节点旁边。如果单词出现在当前节点之后,则将新节点指向current_node->next,然后将current_node->next设置为new_node。

我的问题是,当我试图运行这个程序,使用文件中第二个单词位于第一个单词之前的文件,并试图打印链表时,我会被锁定在一个无限循环中——我已经将问题缩小到某个地方,节点指针没有更新,但我不知道在哪里,我束手无策。

我会附上我的两个文件,如果有人能帮我,我真的很感激

最大频率h

#ifndef MOST_FREQ_H_
#define MOST_FREQ_H_
#include <stdio.h>
//used to hold each "word" in the list
typedef struct word_node
{
char *word;
unsigned int freq; //frequency of word 
struct word_node *next;
} word_node;
struct node *readStringList(FILE *infile);
int readLine(FILE *infile, char * line_buffer);
struct node *getMostFrequent(struct word_node *head, unsigned int num_to_select);
void printStringList(struct word_node *head);
void freeStringList(struct word_node *head);
#endif

most_freq.c

#include "most_freq.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* TODO
0. Check if item is in list (make all strings lowercase)
1a. if not, insert into list
1b. if it is, increment counter for struct */
struct word_node *head = NULL; //unchanging head node
char* str_buffer = NULL;
struct node *readStringList(FILE *infile) {
    char * line = NULL;
    size_t len = 0;
    ssize_t read;
    char* tmp_buffer = (char*) malloc(sizeof(char) * 255);
    while(readLine(infile, tmp_buffer) == 1) {
        if(head == NULL) { //if the linked list is empty
            //allocate space for node
            head = (word_node*) malloc (sizeof(word_node));
            //set as head node
            str_buffer[ strlen(str_buffer) - 1 ] = '';
            head->word = str_buffer; //set string of node to str_buffer
            head->freq = 1; //set frequency to 0
            head->next = NULL; //since we're at the first item of the list there is no next
        }
        else { //else, there is already a node in the list
            printf("Linked list has a node.nn");
            struct word_node *curr = head; //set curr to head (for traversal)
            struct word_node *prev = head; //to keep track of the last node
            while(curr != NULL) {   //while current is not null, continue traversal
                /* If string buffer matches current node's word, then simply update the frequency count */
                if(strcmp(str_buffer,curr->word) == 0) { //if word matches the word in the list
                    curr->freq++; //update the current node's frequency
                    break;
                }
                /* If string buffer comes after current word (in alphabet) then point temp node->next to current->next, and point current node->next to temp */
                else if(strcmp(str_buffer,curr->word) > 1) {
                    printf("Word comes after current node.n");
                    word_node* temp = (word_node*) malloc (sizeof(word_node)); //allocate node for current str_buffer
                    temp->word = str_buffer;
                    temp->next = curr->next; //set temp node->next to current node's next
                    curr->next = temp; //set current->next to point to newly inserted node
                }
                else { //otherwise, str_buffer must come before current node
                    printf("Word comes before current node.n");
                    word_node* temp = (word_node*) malloc (sizeof(word_node)); //allocate node for current str_buffer
                    temp->word = str_buffer;
                    printf("Previous Node: %sn", prev->word);
                    printf("Current Node: %sn", curr->word);
                    prev->next = temp;
                    temp->next = curr;
                }
                prev = curr;
                curr = curr->next; //move current node up by one
            }
        }
    }
    printStringList(head);
    exit(EXIT_SUCCESS);
}
int readLine(FILE *infile, char * line_buffer) {
    char * line = NULL;
    size_t len = 0;
    ssize_t read;
    while ((read = getline(&line, &len, infile)) != -1) {
        line_buffer = line;
        str_buffer = (char*) malloc (sizeof(line));
        strncpy(str_buffer, line_buffer, strlen(line));
        if(str_buffer[0] != '') {
            return 1;
        }
        else
            return -1;
    }
}
void printStringList(struct word_node *top) {
    struct word_node *curr = top; //set curr to head (for traversal)
    printf("List of Strings (and Frequencies)nn");
    int count = 0;
    while(curr != NULL) {
        printf("%s (Frequency: %d)n", curr->word, curr->freq);
        curr = curr->next;
        count++;
    }
    return;
}

int main(int argc, char *argv[])
{
    FILE *file = fopen( argv[1], "r" );
    /* fopen returns 0, the NULL pointer, on failure */
    if ( file == 0 )
    {
        printf( "Could not open file.n" );
    }
    else
    {
        readStringList(file);
    }   
}

测试文本文件(从终端运行时作为参数传入(

foofoo
dog
     else { //otherwise, str_buffer must come before current node
                ....
                prev->next = temp;
                temp->next = curr;

如果列表只有一个节点,那么currprev指向同一节点,并且您在这里引入了一个循环。最初,您将prevcurr都设置为head。最初,您应该将prev设置为NULL,然后在新节点将成为第一个节点时(当prev将成为NULL时(处理

     str_buffer[ strlen(str_buffer) - 1 ] = '';
     head->word = str_buffer; //set string of node to str_buffer

此外,您正在为temp_buffer分配内存,并使用仅作为指针的str_buffer。您可能需要在此处使用temp_buffer

在本部分中:

            else { //otherwise, str_buffer must come before current node
                printf("Word comes before current node.n");
                word_node* temp = (word_node*) malloc (sizeof(word_node)); //allocate node for current str_buffer
                temp->word = str_buffer;
                printf("Previous Node: %sn", prev->word);
                printf("Current Node: %sn", curr->word);
                prev->next = temp;
                temp->next = curr;
            }

您需要为curr == head(或curr == prev(添加一个检查。这种情况需要特殊处理,因为您需要更新head

否则你会得到一个无休止的循环。在这种情况下,您当前的代码实际上是这样做的:

 head->next = newnode;
 newnode->next = head;

这使得列表是循环的(并且在打印时是无休止的循环(。

你需要这样的东西:

if (curr == head)
{
    temp->next = head;
    head = temp;
    ....
}
else
{
    ....
}

除了在特殊情况下需要处理添加到前面以更新head指针之外,我发现readLine例程中的内存分配令人困惑:

char* str_buffer = NULL;                                    // 1
struct node *readStringList(FILE *infile) {
    [...]
    char* tmp_buffer = (char*) malloc(sizeof(char) * 255);  // 2
    while(readLine(infile, tmp_buffer) == 1) {              // 3
int readLine(FILE *infile, char * line_buffer) {
    char * line = NULL;
    while ((read = getline(&line, &len, infile)) != -1) {   // 4
        line_buffer = line;                                 // 5
        str_buffer = (char*) malloc (sizeof(line));         // 6
        strncpy(str_buffer, line_buffer, strlen(line));     // 7

您将为此处读取的每一行执行三(3(个内存分配,其中一个由getline在[4]执行,因为您传入了一个NULL,另一个在[6]的readLine中,第三个在[2]的readStringList中。tmp_buffer([2](在readStringList中的任何位置都没有使用,readLine也没有使用相应的参数(指针只是在[5]处被覆盖(。

此外,这里没有必要使用全局变量[1],函数应该使用它们的参数来传递数据(并且已经有了这些参数(。

由于您使用getline,您可以将其分配的缓冲区返回给外部函数,并在那里直接使用它。

类似这样的东西:

int readLine(FILE *infile, char **line_buffer) {
    char * line = NULL;
    size_t len = 0;
    ssize_t read;
    while ((read = getline(&line, &len, infile)) != -1) {
        *line_buffer = line;
        if(read == 0 || read == -1)
            return -1;
        return 1;
    }
}
struct node *readStringList(FILE *infile) {
    char* str_buffer;
    while(readLine(infile, &str_buffer) == 1) {
        // do something with str_buffer
        // though remember to save it somewhere, you need to free() it later
    }
    [...]

相关内容

  • 没有找到相关文章