新来的,我正在寻求帮助。试着自学C并在网上找到一些作业。 (https://www.cs.cf.ac.uk/Dave/C/node7.html)基本上只是试图通过只找到一个n长度的单词而不是倍数来生成该作业的一部分(练习12337)。我的程序现在计算单词的总数,但我不知道如何超越这一点开始根据它们的长度挑出单词。
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <ctype.h>
int words(const char lne[ ]);
int main()
{
char lne[60], name[25]="";
FILE *fp;
printf("Enter name of the input file: ");
scanf("%s", &name);
if ((fp = fopen(name, "r")) == NULL)
{
printf("File cannot be opened!");
}
else
{
int cntf=-1, cntw=-1;
while (fgets(lne, sizeof lne, fp))
cntf += words(lne);
//cntw += letter(lne);
printf("\nThe most frequent word length is %d", cntf );
printf("\nThe message includes %d words of that length", cntf);
fclose(fp);
}
return 0;
}
int words(const char lne[])
{
int i, count=0;
for (i=0; i<strlen(lne); i++)
{
if (lne[i] == ' '||lne[i] == '\t'||lne[i] == '\n')
count++;
}
return count;
}
答案 0 :(得分:0)
当测量范围内任何事件的频率(字长,字符出现等)时,一种非常简单的方法是声明一个数组,该数组至少包含该范围内的最大元素数(例如,如果你正在计算a-z
的出现次数,您需要至少26
个元素的数组。 (对于单词长度,您需要一个至少为27
的数组 - 未删节字典中最长单词的长度)。如果范围不确定,您可以随时添加一些额外的元素以确保覆盖范围。
必须将数组初始化为0
。然后,对于每次出现,继续a-z
示例,每次遇到a
时,您都会增加与a
相关联的索引(例如0
,{{1} },b=1
)等等。因此,当遇到c=2
时,您的数组名称为a
时,您将增加
charfreq
在您阅读所有字符并增加相关索引后,charfreq[0]++;
中的值是charfreq[0]
的数量,a
charfreq[1]
的数量}&#39; s,等等。
您也可以使用这种精确的方法来收集字长的频率。在找到长度的频率之前,您当然必须找到单词的数量。虽然您可以通过计算每行的空格分隔符并添加b
来手动查找单词数,但这并不能让您获得每个单词的长度(当您计算空格时,您可以沿着字符串向下走2个指针在每个单词之后终止/恢复并获取指针差异),但C库有1
来帮助您为该行标记。
当您对行进行标记时(无论您如何操作),您只需要获取每个标记(字)的长度并更新频率数组 - 您就完成了。 strtok
函数可以在words
的帮助下编写如下(注意strtok
修改原始字符串,因此如果必须保留原文,则需要一份副本)
strtok
将这些部分放在一起,注意文件名通常作为参数传递,您可以执行类似以下操作来读取/处理文件中的单词(或默认情况下来自int words (const char *buf, const char *delims, int *freq)
{
char tmp[MAXC] = ""; /* temp array to hold buf as */
char *p; /* strtok modifies original */
int cnt = 0;
strncpy (tmp, buf, sizeof tmp); /* copy buf to tmp & tokenize */
for (p = strtok (tmp,delims); p; p = strtok (NULL, delims)) {
cnt++;
freq[strlen(p)]++;
}
return cnt;
}
):
stdin
示例输入文件
#include <stdio.h>
#include <string.h>
enum { MAXF = 32, MAXC = 256 };
int words (const char *buf, const char *delims, int *freq);
int main (int argc, char **argv) {
char buf[MAXC] = "";
char *delims = " ,.\t\n"; /* delimiters for strtok */
int cntw = 0, i, midx = 0, mfreq = 0;
int freq[MAXF] = {0};
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file is open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
while (fgets (buf, sizeof buf, fp)) /* read each line */
cntw += words (buf, delims, freq); /* call words */
i = MAXF;
while (i--) /* find longest most frequent length */
if (freq[i] > mfreq) { /* in mfreq, which occurs at */
mfreq = freq[i]; /* midx - most frequent idx */
midx = i;
}
/* output results */
printf (" \n There are '%d' words in the file.\n", cntw);
printf (" The most frequent word length is '%d'\n", midx);
printf (" The message includes '%d' words of that length.\n\n",
mfreq);
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
int words (const char *buf, const char *delims, int *freq)
{
char tmp[MAXC] = ""; /* temp array to hold buf as */
char *p; /* strtok modifies original */
int cnt = 0;
strncpy (tmp, buf, sizeof tmp); /* copy buf to tmp & tokenize */
for (p = strtok (tmp,delims); p; p = strtok (NULL, delims)) {
cnt++;
freq[strlen(p)]++;
}
return cnt;
}
示例使用/输出
$ cat ../dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.
使用$ ./bin/wordsmfreq <../dat/captnjack.txt
There are '16' words in the file.
The most frequent word length is '4'
The message includes '4' words of that length.
代替strcspn
图书馆中还有另一个值得的功能,strtok
。它将扫描字符串以查找未包含在分隔符中的事件。它返回不包含strcspn
列表中任何拒绝字符的初始段的长度。你可以使用该函数在delims
上重复调用,同时将指针推到tmp
以完成tmp
所做的事情。 (无需拨打strtok
)
查看示例,如果您有任何问题,请告诉我。