程序将无法运行 - 书籍计算器的字母频率

时间:2016-11-17 20:18:21

标签: c

我试图找到频率这个词,我无法弄清楚为什么程序一直在崩溃..我已经尝试了很多方法,但我仍然遇到同样的崩溃。难道我做错了什么? *输入是一个书籍文件和我想要创建的新文件。

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

int main( int argc, char *argv[] )
{
    FILE *fp,*fp2;
    int ch, total, counter, totalcounter, i;
    int letters[25], letterfrequency[25];
    for(i=0; i<25; i++)
    {
        letters[i] = 0;
        letterfrequency[i] = 0;
    }
    printf("Opening: %s", argv[1]);
    fp = fopen(argv[1], "r");
    if (!fp)
        {
            perror("fopen");
            exit(1);
        }
    while((ch=fgetc(fp)) != EOF)
        {
            if((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
                {
                    counter = toupper(ch);
                    ch = counter - 65;
                    letters[ch]++;
                    totalcounter++;
                }
        }

    fp2 = fopen(argv[2], "w");
    for(i=0;i<25;i++)
    {
        fprintf(fp2, "%c: Times used: %s\tFrequency Used: %s", i+65, letters[i], letters[i]/totalcounter);
    }
    fclose(fp);
    fclose(fp2);
    return 0;
}

2 个答案:

答案 0 :(得分:3)

您的代码存在许多问题。首先是它有警告。这些警告指出了问题。不幸的是,大多数C编译器默认情况下不会向您显示警告。您必须使用-Wall启用它们。但-Wall并不代表“所有警告”,哦不。如果你问为什么,简短的回答是C是数十年可疑设计选择的积累,习惯它。 : - /我运行了更多的警告和检查:-Wall -Wwrite-strings -Wextra -Wconversion -std=c99 -pedantic -g

有一堆未使用和未初始化的变量,你的printf规范是错误的,而你错过了include toupper。我会让你解决所有问题。

接下来的问题是你将letters初始化为25长,但字母表有26个字符。幸运的是,你也只是迭代了25次,但这意味着你将失去'Z'。这是一个容易犯的错误。 26项长数组从0到25,但其长度为26。

不是在整个地方重复数组的长度,而是可能错过一个,最好在一个地方定义它。

#define NUM_LETTERS 26

然后有一种更快速,更简单的方法来初始化数组。

int letters[NUM_LETTERS] = {0};

没有必要指定每个元素,C将用最后一个元素填充其余元素。

由于在非某个字符的内容上调用toupper是完全安全的,它只会使字符不变,您可以简化while循环。

while((ch=fgetc(fp)) != EOF) {
    ch = toupper(ch);
    if( 'A' <= ch && ch <= 'Z' ) {
        ch -= 65;
        letters[ch]++;
        totalcounter++;
    }
}

请注意我使用的样式'A' <= ch && ch <= 'Z'。这样可以更轻松地查看从chA范围内检查Z

下一个问题是:letters[i]/totalcounter

在C中,如果你除以两个整数,你会得到一个整数。这意味着20/1000。如果需要小数,则必须将其中一个变量转换为浮点类型:(double)letters[i]/totalcounter)

可能没有从文件中读取字母而totalcounter为0.如果是这样letters[i]/totalcounter将导致被零除错误。所以你必须检查那个案例。

if( totalcounter != 0 ) {
    for( i=0; i<NUM_LETTERS; i++ ) {
        printf("%c: Times used: %d\tFrequency Used: %f\n",
               i+65, letters[i], (double)letters[i]/totalcounter
        );
    }
}
else {
    printf("No letters found.\n");
}

您无法检查用户是否为您提供了文件名参数。如果他们不这样做,你的程序将崩溃。添加使用情况检查非常重要。

if( argc < 2 ) {
    fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
    exit(1);
}

请注意,我没有将结果写入文件,而且我的版本只有一个文件,一个要阅读的文件。我的版本输出到stdout。

通常,将程序结果打印到stdout比打印到文件更好。这使程序能够很好地与外壳管道配合使用,使其更加灵活。

./wordcount somefile                      # output to the screen
./wordcount somefile.txt > somefile.count # output to a file
./wordcount somefile.txt | program        # output to another program

答案 1 :(得分:1)

更改您的数组以获取所有字母,即int letters[26];另一个letterfrequence您似乎不会用于任何事情

您的fprintf格式说明符错误

你有

fprintf(fp2, "%c: Times used: %s\tFrequency Used: %s", i+65, letters[i], letters[i]/totalcounter);

但是letters是一个int数组,所以正确的说明符应该是%d(int)而不是%s(string)

您尚未初始化totalcounter,因此可能会发生0分割或其他任意分割。

toupper位于标题ctype.h中,标题丢失。