我正在尝试编写一个程序,该程序将计算段落中单词的出现次数。
我遵循的逻辑是:我使用的是链接列表。我正在按顺序搜索——如果遇到新单词在列表中添加单词,但如果单词已经存在于列表中,则增加其计数标志。
//case insensitive string matching
int strcicmp(char const *a, char const *b)
{
int d;
for(;;a++,b++)
{
d=tolower(*a)-tolower(*b);
if(d!=0 || !*a)
return d;
}
}
//declare the linked list structure to store distinct words and their count
typedef struct node
{
char *word;
int count;
struct node *next;
} node;
node *ptr, *newnode, *first=NULL, *last=NULL;
void insertnewword(char *ch)
{
newnode=(node*)malloc(sizeof(node));
if(newnode == NULL)
{
printf("nMemory is not allocatedn");
exit(0);
}
else
{
newnode->word=ch;
newnode->count=1;
newnode->next=NULL;
}
if(first==last && last==NULL)
{
first=last=newnode;
first->next=NULL;
last->next=NULL;
}
else
{
last->next=newnode;
last=newnode;
last->next=NULL;
}
}
void processword(char *ch)
{
int found=0;
//if word is already in the list, increase the count
for(ptr=first;ptr!=NULL;ptr=ptr->next)
if(strcicmp(ptr->word, ch) == 0)
{
ptr->count += 1;
found=1;
break;
}
//if it's a new word, add the word to the list
if(!found)
insertnewword(ch);
}
int main()
{
const char *delimiters=" ~`!@#$%^&*()_-+={[}]:;<,>.?/|\'"tnr";
char *ch, *str;
str=(char*)malloc(sizeof(char));
ch=(char*)malloc(sizeof(char));
//get the original string
scanf("%[^n]%*c", str);
//fgets(str, 500, stdin);
//get the tokenized string
ch=strtok(str,delimiters);
while(ch!=NULL)
{
//a, an, the should not be counted
if(strcicmp("a", ch)!=0 && strcicmp("an", ch)!=0 && strcicmp("the", ch)!=0)
processword(ch);
ch=strtok(NULL,delimiters);
}
//print the word and it's occurrence count
for(ptr=first; ptr!=NULL; ptr=ptr->next)
printf("%stt%dn",ptr->word,ptr->count);
return 0;
}
这似乎对少数单词有效,但如果单词计数超过6-7,则该程序会遇到一些问题。
说输入是:我是一个好男孩。我是个坏男孩。
输入应为
I 2上午2点良好1坏1男孩2
但我得到的是I 2上午2点良好1坏1(一些垃圾字符)1
对于同一个问题,我总是可以实现任何其他逻辑,但我想知道这个实现的问题。
提前感谢
我认为问题来自您的扫描f:
in the man scanf:
the next pointer must be a pointer to char, and there must be enough room for all the characters in the string, plus a terminating null byte
但在main的顶部,char数组的分配只有一个长度:str=(char*)malloc(sizeof(char));
我认为使用getline 这样的功能会更好
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
并将lineptr设置为指向NULL
我认为你的链表实现并没有给你带来问题,但你的内存分配给你带来了实际的问题。
第一个内存分配问题:
str=(char*)malloc(sizeof(char));
ch=(char*)malloc(sizeof(char));
这里str和ch应该有内存来保存完整的单词和终止的null字符,但您只分配了一个字节(即char的大小)
第二个内存分配问题:
newnode->word=ch;
这个代码片段存在于insertnewword()函数中。在这里,您已经为新节点分配了内存,但没有为新节点内的字符分配任何内存。之后,直接使newnode->word指向ch,ch是main()函数的局部变量。当您完成第一个单词并进一步标记输入字符串时,ch包含字符串中的下一个单词。现在,这可能会破坏你的链接列表中的数据,因为你已经使newnode->word直接指向ch。
因此,请将内存分配给newnode中的单词字段,并将ch的内容复制到其中。
我希望这能解决你的问题。