【问题标题】:C code to count the number of characters, words and lines in a file计算文件中字符数、单词数和行数的C代码
【发布时间】:2019-02-23 18:56:16
【问题描述】:

我是 C 的初学者,所以我想看看一个代码,它包括计算给定文件中的字符数、单词数和行数。我发现了下面的代码,但问题是我不明白为什么我们必须在 while 循环之后为最后一个单词增加单词和行:if (characters > 0)...

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

int main() {
    FILE *file;
    char path[100];
    char ch;
    int characters, words, lines;

    /* Input path of files to merge to third file */
    printf("Enter source file path: ");
    scanf("%s", path);

    /* Open source files in 'r' mode */
    file = fopen(path, "r");

    /* Check if file opened successfully */
    if (file == NULL) {
        printf("\nUnable to open file.\n");
        printf("Please check if file exists and you have read privilege.\n");
        exit(EXIT_FAILURE);
    }

    /*
     * Logic to count characters, words and lines.
     */
    characters = words = lines = 0;
    while ((ch = fgetc(file)) != EOF) {
        characters++;

        /* Check new line */
        if (ch == '\n' || ch == '\0')
            lines++;

        /* Check words */
        if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\0')
            words++;
    }

    /* Increment words and lines for last word */
    if (characters > 0) {
        words++;
        lines++;
    }

    /* Print file statistics */
    printf("\n");
    printf("Total characters = %d\n", characters);
    printf("Total words      = %d\n", words);
    printf("Total lines      = %d\n", lines);

    /* Close files to release resources */
    fclose(file);

    return 0;
}

【问题讨论】:

  • char ch; -->> int ch; (并且:你不是在计算单词,你是在计算空白字符)
  • 拥有 int ch 的目标是与 EOF 兼容
  • 假设输入文件不以换行符结尾。尝试使用包含“foo”的 3 字节长文件(而不是像往常一样的“foo\n”)。 [我说那个文件(3 字节“foo”)有 3 个字符、1 个单词和 0 行;但您的程序可能有其他意见。]
  • scanf("%s", path); – 切勿在未指定 width 的情况下使用转换说明符 %s 来限制写入目标的字符数。对于char path[100]; 使用scanf("%99s", path); ... 99 + 终止'\0' = 100。同时定义/声明变量尽可能接近它们的使用位置。它是int main(void)

标签: c file


【解决方案1】:

这个程序有一些问题:

  • ch 必须定义为 int 才能正确检测到 EOF

  • scanf("%s", path); 的过长输入将溢出path 并导致未定义的行为。还要检查返回值以检测无效输入或文件过早结束:

    if (scanf("%99s", path) != 1)
        return 1;
    
  • 测试ch == '\0' 来计算行数是有争议的。标准的wc unix 实用程序不会将空字节视为行分隔符。

  • if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\0') 也不是检测字边界的标准方法。 if (isspace(ch)) 更惯用。

  • 字数不正确:多个空格将被视为多个字!您应该改为检测边界,即空格字符后跟非空格字符。

  • 最后的测试是解决上述问题的蹩脚尝试,它还不够。如果流不以换行符结束,则确实需要额外的测试来计算流的最后一个。

这是一个更正的版本:

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

int main() {
    FILE *file;
    char path[1024];
    int ch, last;
    long long int characters, words, lines;

    /* Input path of files to merge to third file */
    printf("Enter source file path: ");
    if (scanf("%255s", path) != 1) {
        printf("Invalid input\n");
        return EXIT_FAILURE;
    }

    /* Open source files in 'r' mode */
    file = fopen(path, "r");

    /* Check if file opened successfully */
    if (file == NULL) {
        printf("Unable to open file %s\n", path);
        printf("Please check if file exists and you have read privilege.\n");
        return EXIT_FAILURE;
    }

    /*
     * Logic to count characters, words and lines.
     */
    characters = words = lines = 0;
    last = '\n';
    while ((ch = fgetc(file)) != EOF) {
        characters++;

        /* Check new line */
        if (ch == '\n')
            lines++;

        /* Check words */
        if (!isspace(ch) && isspace(last))
            words++;

        last = ch;
    }

    /* Increment words and lines for last word */
    if (last != '\n') {
        lines++;
    }

    /* Print file statistics */
    printf("\n");
    printf("Total characters = %lld\n", characters);
    printf("Total words      = %lld\n", words);
    printf("Total lines      = %lld\n", lines);

    /* Close file to release resources */
    fclose(file);

    return 0;
}

【讨论】:

    【解决方案2】:

    需要根据输入的输入文件调整输出是否以漂亮的换行符('\n')字符结尾。

    对于在所有行(包括最后一行)上都以“\n”结尾的纯文本文件,请删除循环后的那些增量。

    但似乎需要针对这些极端情况对程序进行一些调试,这取决于您的定义。但我强烈建议使用 Linux/Unix 命令wc 作为参考和决胜局。

    【讨论】:

      猜你喜欢
      • 2018-06-02
      • 1970-01-01
      • 2013-02-20
      • 2014-02-20
      • 1970-01-01
      • 1970-01-01
      • 2011-07-27
      • 2019-02-21
      • 2023-03-12
      相关资源
      最近更新 更多