“如何使我的程序从文件中读取可见的字符和空格

时间:2019-05-05 22:10:32

标签: c

我应该给我“固定”代码,以使其在文件中显示正确数量的可见字符(也包括空格)。正确的数字应该是977。我以前从未处理过文件,而且我不知道显示正确的数字需要做什么。

 * Driver Menu System for Homework
 * Andrew Potter - Mar 5, 2019  <-- Please put your name/date here
 */

#include <stdio.h>//header file for input/output -
#include <stdlib.h>
#include <ctype.h>
// since you will place all your assigned functions (programs) in this file, you do not need to include stdio.h again!

int menu(void);   //prototype definition section
void hello(void);
void countall(void);

int main(void)
{
    int selection = menu();

    while(selection != 99) {

        switch(selection) {

        case 1:
           hello();
           break;

        case 2:
            countall();
           break;

        case 3:

           break;

        case 4:

           break;

         default:
            printf("Please enter a valid selection.\n");
        }

    selection = menu();
    }

   return 0;
}

int menu(void) {
    int choice;
    printf("***************************\n");
    printf(" 1. Hello \n");
    printf(" 2. Countall\n");
    printf(" 3. \n");
    printf(" 4. \n");
    printf("99. Exit\n");
    printf("Please select number and press enter:\n");
    printf("***************************\n");
    scanf("%d", &choice);
    getchar();
    return choice;
}

void hello(void) {
    printf("Hello, World!!!\n");
}

//*****Andrew 5/1/19*****

#define SLEN 81    /* from reverse.c */
/* original header: int count(argc, *argv[]) */
void countall(void)
{
    int ch;         // place to store each character as read
    FILE *fp;       // "file pointer"
    long unsigned count = 0;
    char file[SLEN];  /* from reverse.c */

    /*Checks whether a file name was included when run from the command prompt
     * The argument count includes the program file name. A count of 2 indicates
     * that an additional parameter was passed
    if (argc != 2)
    {
        printf("Usage: %s filename\n", argv[0]);
        exit(EXIT_FAILURE);
    }
     * The following uses the second parameter as the file name
     * and attempts to open the file
    if ((fp = fopen(argv[1], "r")) == NULL)
    {
        printf("Can't open %s\n", argv[1]);
        exit(EXIT_FAILURE);
    } */

    /*************************************
     Code from reverse.c included to make the program work from within our IDE
     *************************************/
    puts("Enter the name of the file to be processed:");
    scanf("%s", file);

    if ((fp = fopen(file,"rb")) == NULL)   /* read mode */
    {
        printf("count program can't open %s\n", file);
        exit(EXIT_FAILURE);
    }

    /* EOF reached when C realizes it tried to reach beyond the end of the file! */
    /* This is good design - see page 573  */
    while ((ch = getc(fp)) != EOF)
    {
      if (isprint(ch)) {
          count++;
} 
      else if (isprint(ch)) {
        count++;
} 
        putc(ch,stdout);  // same as putchar(ch);
        count++;
    }
    fclose(fp);
    printf("\nFile %s has %lu characters\n", file, count);
}

我期望使用isprint和isspace的组合可以得到正确数量的可见字符,但是我通常会得到2086。 分配方向为:“ Word识别977个字符,包括空格。您当前的countall()认为有1043个。对代码进行必要的更正以仅计算可见字符和空格!(提示:在教科书中查看567。) “在我编辑任何代码之前,计数是1043,现在是2020。我需要977。

3 个答案:

答案 0 :(得分:2)

isprint()返回一个布尔结果-如果字符不是“可打印的”,则返回零,否则返回非零。因此isprint(ch) != '\n'没有任何意义。您在问题中的完整表达甚至没有意义,但是我将在最后继续进行说明。

isprint()本身对所有可打印字符都返回true(非零),因此您不需要其他测试。此外,您无条件地在每个条件块中递增count,因此您要对每个字符计数,而有些则要计数两次。

您只需要:

if( isprint(ch) )
{ 
    count++; 
}
putc( ch, stdout ) ;

虽然您的代码显然是不完整的片段,但不清楚您在哪里或如何阅读ch。您那里需要getc()或同等学历。

while( (ch = getc(fp)) != EOF ) 
{
    if( isprint(ch) )
    { 
        count++; 
    }
    putc( ch, stdout ) ;
}

目前尚不清楚您是否需要计算所有空格(包括空格,制表符和换行符)还是仅计算“空格”。如果是这样,请注意isprint()将匹配空格,但不能匹配换行符或制表符。 isspace()与所有这些都匹配,但不应单独计入isprint(),因为'space'既包含空白又包含可打印的集合。如果要计算换行符和制表符(可能性不大;“垂直制表符”),则:

while( (ch = getc(fp)) != EOF ) 
{
    if( isprint(ch) || isspace(ch) )
    { 
        count++; 
    }

    putc( ch, stdout ) ;
}

您似乎会误解的C的另一方面是布尔表达式如何工作。要测试单个变量的多个值,您必须编写:

if( var == x || var == y || var == z )

您写了:

if( var == x || y || z )

当您大声朗读它时,这可能在英语(或其他自然语言)中有意义,但在C语言中则表示:

if( var == (x || y || z ) )

(x || y || z )评估为truefalse并将其与var进行比较。

可能值得考虑您现有解决方案的语义,以显示其实际编译的原因,但会产生它执行的错误结果。

首先,

  isprint(ch) != '\n' || '\t' || '\0' 
出于先前所述的原因,

等效于isprint(ch) != true。因此,您可以为不可打印的所有字符增加计数器。

然后在这里

  isspace(ch) == NULL

NULL是表示无效指针的宏,而isspace()不返回指针。但是NULL将隐式转换为零(或为false)。因此,在这里您可以为不是空格的所有可打印字符增加计数器。

最后,您无条件在这里计算每个字符:

    putc(ch,stdout);  // same as putchar(ch);
    count++;

所以您的结果将是:

number-of-non-printing-characters + 
number-of-printing-characters - number-of-spaces +
total-number-of-characters

我认为是(2 x file-length) - number-of-spaces

最后请注意,如果在“二进制”模式下打开CR + LF行尾(Windows上的常规文本文件)的文本文件,isspace()将为每个换行计算两个字符。确保以“文本”模式打开(无论平台如何)。

答案 1 :(得分:1)

来自isprint()

  

可打印字符是在显示器上占据打印位置的字符(与控制字符相反,用iscntrl进行检查)。

  

如果c确实是可打印的字符,则该值不同于零(即true)。否则为零(即false)。

因此该功能应该足够了。请注意,您必须确保从is...()个无符号值中输入所有这些<ctype.h>函数。因此,如果您使用不确定来源的值,最好将其转换为char unsigned

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

int main(void)
{
    char const *filename = "test.txt";
    FILE *input = fopen(filename, "r");
    if (!input) {
        fprintf(stderr, "Couldn't open \"%s\" for reading. :(\n\n", filename);
        return EXIT_FAILURE;
    }

    long long unsigned count = 0;   
    for (int ch;  (ch = fgetc(input)) != EOF;) {
        if (isprint(ch))
            ++count;
    }

    fclose(input);
    printf("Count: %llu\n\n", count);
}

如果我不太幸运地猜出要计算哪些字符,请查看ctype.h,那里有一张桌子。

答案 2 :(得分:0)

if ((ch == '\t') || isprint(ch))
        count++;

如果您想以不同的方式处理制表符(也许要计算它们使用了多少空格):

if (ch == '\t') {
        /* Do smth */
} else if (isprint(ch)) {
        count++;
}

这应该足够了。