我试图在插入链接列表时按字母顺序排列(从文件中(-我目前有三个检查(我会用它来解释我的逻辑-如果有人有更好的想法,请告诉我,我已经为此烦恼了一整天(:
如果从文件中获取的单词与当前节点中的单词匹配,只需增加节点中的频率计数器即可(无需创建新节点(。如果单词出现在当前节点之前,则将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;
如果列表只有一个节点,那么curr
和prev
指向同一节点,并且您在这里引入了一个循环。最初,您将prev
和curr
都设置为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
}
[...]