不能算'|' .c文件中的符号

时间:2016-01-18 22:43:51

标签: c file fgetc charactercount

基本上我必须编写一个程序来计算.c文件中各种不同的符号。除了垂直线“|”之外,我还使用了所有需要的符号。出于某种原因,它只是不计算它们。

这是我正在使用的方法:

int countGreaterLesserEquals(char filename[])
{
    FILE *fp = fopen(filename,"r");
    FILE *f;
    int temp = 0; // ASCII code of the character
    int capital = 0;
    int lesser = 0;
    int numbers = 0;
    int comments = 0;
    int lines = 0;
    int spc = 0;

    if (fp == NULL) {
        printf("File is invalid\\empty.\n");
        return 0;
    }

    while ((temp = fgetc(fp)) != EOF) {

        if (temp >= 'a' && temp <= 'z') {
            capital++;
        }
        else if (temp >= 'A' && temp <= 'Z') {
            lesser++;
        }
        else if( temp == '/') temp = fgetc(fp); {
            if(temp == '/')
                comments++;             
        }

        if (temp >= '0' && temp <= '9') {
            numbers++;
        }
        if (temp == '|') {
            spc++;
        }
        if (temp == '\n') {
            lines++;
        }
    }
}

2 个答案:

答案 0 :(得分:3)

在这一行:

else if( temp == '/') temp = fgetc(fp); {

我相信你错位{。据我所知,它应该在temp = fgetc(fp);之前......

如果按照编码风格指南将每个表达式放在其自己的行上并正确缩进代码,则可以轻松避免此类错误。

更新:此fgetc是一个极端情况。如果您在这里阅读过EOF怎么办?您没有检查此错误。

答案 1 :(得分:3)

首先,一些编译器警告:

  • &#39; F&#39; :未引用的局部变量
  • 并非所有控制路径都返回值

因此,f可以删除,函数也应该返回成功值。在最高级别设置编译器警告总是一个好主意。

然后,出现了问题:

else if( temp == '/') temp = fgetc(fp); {
    if(temp == '/')
        comments++;             
}

检查;末尾的else。这意味着它后面的块总是被执行。此外,对于此fgetc(),不会检查EOF或错误。

此外,如果temp/,但后面的字符不是,则会跳过它,因此我们需要将字符放回流中(在这种情况下最简单的解决方案)。

以下是一个完整的例子:

int countGreaterLesserEquals(char filename[])
{
    FILE *fp = fopen(filename, "r");
    int temp     = 0; // ASCII code of the character
    int capital  = 0;
    int lesser   = 0;
    int numbers  = 0;
    int comments = 0;
    int lines    = 0;
    int spc      = 0;

    if (fp == NULL) {
        printf("File is invalid\\empty.\n");
        return 0;
    }

    while ((temp = fgetc(fp)) != EOF) {

        // check characters - check most common first
        if      (temp >= 'a' && temp <= 'z') lesser++;
        else if (temp >= 'A' && temp <= 'Z') capital++;
        else if (temp >= '0' && temp <= '9') numbers++;
        else if (temp == '|')                spc++;
        else if (temp == '\n')               lines++;
        else if( temp == '/')
            if ((temp = fgetc(fp)) == EOF)
                break; // handle error/eof
            else
                if(temp == '/')              comments++;
                else ungetc(temp, fp); // put character back into the stream
    }

    fclose (fp); // close as soon as possible

    printf("capital:  %d\nlesser:   %d\ncomments: %d\n"
           "numbers:  %d\nspc:      %d\nlines:    %d\n",
           capital, lesser, comments, numbers, spc, lines
    );

    return 1;
}

虽然通常建议将if语句放在花括号中,但我认为在这种情况下,为了清楚起见,我们可以将它们放在同一行上。

在这种情况下,每个if前面都可以加else。这样,当一个人已经找到时,程序不必检查剩余的情况。由于同样的原因,最常放置对最常见字符的检查(但情况确实如此)。

作为替代方案,您可以使用islower(temp)isupper(temp)isdigit(temp)来处理前三种情况。

<强>性能

为了完整起见:虽然这可能是对小文件的练习,但对于较大的文件,应该在缓冲区中读取数据以获得更好的性能(甚至在文件上使用内存映射)。

更新@SteveSummitfgetc效果的评论:

  

答案很好,但我不同意你关于表现的说明   结束。 fgetc已经缓存了!所以性能直截了当   这样的代码即使对于大输入也应该没问题;通常是这样的   由于担心&#34;效率&#34;而无需使代码复杂化。

虽然这个评论起初似乎是有效的,但我真的想知道性能的真正区别是什么(因为我以前从未使用fgetc我之前没有测试过),所以我写了一个小测试程序:

打开一个大文件并将每个字节加到uint32_t中,这与扫描上面某些字符相当。操作系统磁盘缓存已经缓存了数据(因为我们正在测试功能/扫描的性能,而不是硬盘的读取速度)。虽然上面的示例代码最有可能是小文件,但我想我也可以在这里放大文件的测试结果。

这些是平均结果:

- using fgetc                                        : 8770
- using a buffer and scan the chars using a pointer  :  188
- use memory mapping and scan chars using a pointer  :  118

现在,我非常确定使用缓冲区和内存映射会更快(我一直使用那些更大的数据),速度的差异甚至比预期的还要大。好的,fgetc可能会有一些可能的优化,但即使这些优化速度加倍,差异仍然很大。

底线:是的,为更大的文件优化此功能是值得的。例如,如果使用buffers / mmap处理文件数据需要1秒钟,那么使用fgetc会花费一分钟!