计算文件中的字符我找不到什么错误

时间:2018-04-27 16:02:59

标签: c

为什么这个函数不会计算文本中的字符?我在main函数中打开文件,包括countchars.also文件是从countchars之前的函数打开但是我在countchars结束时关闭它。为什么fscanf没有!= EOF只读取最后一个字母?

void countchars(FILE *p){
        char ch;
        int countc=0;
        for(;(fscanf(p,"%c",&ch)!=EOF);countc++);
        printf("%d",countc);

REST代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int getchoice(void);
void inserttextfromfile();
void printtextdata(FILE *);
void countwords(FILE *);
void calculatetextstatistics();
void countchars(FILE *);
int main(){ 
    int a;
    while((a=getchoice())){
      switch (a){
            case 1:
                  break;
            case 2:    ;
                  break;
            case 3:    ;
                  break;
            case 4:    ;
                  break;
            case 5:calculatetextstatistics() ;
                  break;
            case 6:    ;
                  break;
            default: break;
        }
    }


    return 0;
}
int getchoice(){
    int a;
    scanf("%d",&a);
    return a;
}

void calculatetextstatistics(){
    FILE *p;
    p=fopen("mytext.txt","rt");
    countwords(p);
    countchars(p);
    fclose(p);
}
void countwords(FILE *p){
    int countw=0;
    char wordholder[10]=" ";
    char wordlist[60][10];
    for (;(fscanf(p,"%s",wordholder))!= EOF;countw++);
    printf("%d\n",countw);
    return;
}
void countchars(FILE *p){
    char ch;

    int countc=0;
    for(;(fscanf(p,"%c",&ch)!=EOF);countw++);
    printf("%d",countw);

}

2 个答案:

答案 0 :(得分:3)

您读取文件内容的方法效率很低但应该有效,除非流指针p具有无效值,例如NULL

用于此目的的经典代码是:

#include <stdio.h>

void countchars(FILE *fp) {
    int ch;
    int countc = 0;
    while ((c = getc(fp)) != EOF)
        countc++;
    printf("%d\n", countc);
}

您的功能失败,因为该流已被读取到文件末尾。您可以使用rewind(fp);fseek(fp, 0L, SEEK_SET);将文件流重置为文件的开头,但并非所有流都可以通过这种方式重绕。例如,无法重新启动从控制台读取。

计算单词的功能被破坏:如果文件中的任何单词超过9个字节,则表示您有未定义的行为。您应该一次读取一个字符并计算从空格到非空格字符的转换次数:

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

void countwords(FILE *fp) {
    int countw = 0;
    int c, lastc = '\n';

    while ((c = getc(fp)) != EOF) {
        countw += isspace(lastc) && !isspace(c);
        lastc = c;
    }
    printf("%d\n", countw);
}

如果您坚持使用fscanf(),可以选择以下方法:

void countwords(FILE *fp) {
    int countw = 0;
    char c, lastc = '\n';

    while (fscanf(fp, "%c", &c) == 1) {
        countw += isspace((unsigned char)lastc) && !isspace((unsigned char)c);
        lastc = c;
    }
    printf("%d\n", countw);
}

答案 1 :(得分:3)

显示实际代码时

你有:

FILE *p;
p=fopen("mytext.txt","rt");
countwords(p);
countchars(p);
fclose(p);

由于countwords()读取到EOF,countchars()会立即获得EOF。使用:

FILE *p;
p=fopen("mytext.txt","rt");
countwords(p);
rewind(p);
countchars(p);
fclose(p);

这会在countwords()达到EOF后将文件流倒回到文件的开头,以便countchars()可以重新读取该文件。请注意,这仅适用于常规磁盘文件;它不适用于管道,终端,插座,因为你无法寻找那些。有一些相当简单的方法可以对数据进行单次传递,以计算字符和单词,而无需重新读取数据。但是,这些超出了这个问题的直接范围。

这也完美地证明了MCVE(Minimal, Complete, Verifiable Example)的重要性。这使得解决问题变得微不足道 - 没有MCVE,就没有问题需要解决。

请注意,getchoice()的代码和main()中的大转换对MCVE来说并不重要。我还必须修复示例中的代码以使其编译。

这是代码的最小化版本:

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

void countwords(FILE *);
void calculatetextstatistics(void);
void countchars(FILE *);

int main(void)
{
    calculatetextstatistics();

    return 0;
}

void calculatetextstatistics(void)
{
    FILE *p = fopen("mytext.txt", "rt");
    countwords(p);
    rewind(p);
    countchars(p);
    fclose(p);
}

void countwords(FILE *p)
{
    int countw = 0;
    char wordholder[80] = " ";
    for ( ; (fscanf(p, "%s", wordholder)) != EOF; countw++)
        ;
    printf("%d\n", countw);
}

void countchars(FILE *p)
{
    char ch;
    int countc = 0;

    for ( ; (fscanf(p, "%c", &ch) != EOF); countc++)
        ;
    printf("%d\n", countc);
}

当我将其来源链接到mytext.txt时,它会提供输出83 695,而wc -wc也会给出相同的答案。

第一次通过

鉴于这样的MCVE:

#include <stdio.h>

static void countchars(FILE *p)
{
    char ch;
    int countc = 0;
    for ( ; (fscanf(p, "%c", &ch) != EOF); countc++)
        ;
    printf("%d", countc);
    putchar('\n');
}

int main(void)
{
    countchars(stdin);
    return 0;
}

并将其编译为程序cc17,并在其自己的源上运行:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror cc17.c -o cc17 
$ ./cc17 < cc17.c
254
$

这表明您显示的代码“有效” - 问题出在您未显示的代码中。