当我插入链接列表时(我从文件中插入)尝试按字母顺序排列 - 我目前有三张支票(我将使用它来解释我的逻辑 - 如果有人有更好的想法,请让我知道,我整天都把头发拉过来了):
如果从文件中抓取的单词与当前节点中的单词匹配,只需增加节点中的频率计数器(不要打扰创建新节点)。如果该单词位于当前节点之前,则指向新创建的节点旁边的上一个>,并指向当前节点旁边的new_node->。如果该字出现在当前节点之后,则将新节点指向current_node-> gt;然后在new_node旁边设置current_node->。
我的问题是,当我尝试运行这个程序并使用一个文件,其中文件中的第二个单词出现在第一个单词之前,并尝试打印链表时,我被锁定在无限循环中 - 我&#39我已经把这个问题缩小到某个地方,一个节点指针没有得到更新的事实,但我不知道在哪里,我知道我的结局。
我会附上我拥有的两个文件,如果有人可以帮助我,我真的很感激。 (那里有一些调试线并不是真的有必要,我用它们来试图找出问题所在。)
most_freq.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 ] = '\0';
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.\n\n");
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: %s\n", prev->word);
printf("Current Node: %s\n", 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] != '\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)\n\n");
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
答案 0 :(得分:1)
else { //otherwise, str_buffer must come before current node
....
prev->next = temp;
temp->next = curr;
如果列表中只有一个节点,那么curr
和prev
指向同一个节点,并且您在此处引入了一个循环。最初您要设置prev
和{{1} } curr
。您最初应将head
设置为prev
,然后在新节点将成为第一个节点时处理该情况(NULL
将prev
NULL
1}})
str_buffer[ strlen(str_buffer) - 1 ] = '\0';
head->word = str_buffer; //set string of node to str_buffer
此外,您正在为temp_buffer
分配内存并使用仅仅是指针的str_buffer
。您可能希望在此使用temp_buffer
。
答案 1 :(得分:0)
在这部分:
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: %s\n", prev->word);
printf("Current Node: %s\n", 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
{
....
}
答案 2 :(得分:0)
除了需要处理添加到前面作为更新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
,另一个在{{1}在[6],在[{1}}在[2]的第三个。 readLine
([2])在readStringList
中的任何地方都没有使用,tmp_buffer
也没有使用相应的参数(指针只是在[5]处被覆盖)。
此外,这里不需要使用全局变量[1],你的函数应该使用它们的参数来传递数据(并且已经有了这些参数)。
由于您使用readStringList
,您只需将其分配的缓冲区返回到外部函数,并直接在那里使用。
这样的事情:
readLine