"Как заставить мою программу читать видимые символы и пробелы из файла - PullRequest
0 голосов
/ 06 мая 2019

Я должен был исправить код, данный мне, чтобы он отображал правильное количество видимых символов в файле (пробелы тоже). Предполагается, что правильным номером будет 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 ]

2 голосов
/ 06 мая 2019

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(), потому что «пробел» находится как в пробелах, так и в печатных наборах. Если новая строка и табуляция должны быть подсчитаны (и менее вероятно; «вертикальная табуляция»), то:

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 ) как true или false и сравнивая его с var.

Вероятно, стоит рассмотреть семантику вашего существующего решения, чтобы показать, почему оно на самом деле компилируется, но дает ошибочный результат.

Во-первых,

  isprint(ch) != '\n' || '\t' || '\0' 

эквивалентно isprint(ch) != true по причинам, описанным ранее. Таким образом, вы увеличиваете счетчик для всех символов, которые не для печати. ​​

Тогда вот:

  isspace(ch) == NULL

NULL - это макрос, представляющий недопустимый указатель, а isspace() не возвращает указатель. Однако NULL будет неявно приводить к нулю (или ложь). Таким образом, здесь вы увеличиваете счетчик для всех печатаемых символов, которые не пробелы.

Наконец, вы безоговорочно отсчитываете здесь каждый символ:

    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 голос
/ 06 мая 2019

С isprint():

Печатный символ - это символ, который занимает позицию печати на дисплее (это противоположность контрольного символа, проверяется с помощью iscntrl).

и

Значение, отличное от нуля (т. Е. Истина), если действительно c является печатным символом.Ноль (т. Е. Ложь) в противном случае.

Так что этой функции должно быть достаточно.Пожалуйста, обратите внимание, что вы должны обязательно передать все эти 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, есть таблица.

0 голосов
/ 06 мая 2019
if ((ch == '\t') || isprint(ch))
        count++;

Если вы хотите обрабатывать вкладки по-разному (возможно, для подсчета количества используемых ими пробелов):

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

Этого должно быть достаточно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...