Как отобразить количество записей в файле? - PullRequest
0 голосов
/ 24 апреля 2020

Сценарий выглядит следующим образом:

Медицинский центр должен хранить сведения о приеме в текстовом файле с именем meeting.dat.

Включает Имя пациента и тип встречи. Типы встреч могут быть «Консультация» , «Сканирование» или «Тестирование» . В файле сохраняется только первая буква.

Требуется:

  1. Создать файл appointment.dat
  2. Получить 5 сведений о пациенте с помощью ввода с клавиатуры и запишите данные в файл appointment.dat в указанном формате.
  Dave                C
  Ryan                T
  Mary                S
  George              C
  Julian              S
Считайте файл appointment.dat, рассчитайте и отобразите количество пациентов в заданном формате.
  Appointment Type       Number of patients
  Consulting                     2
  Scanning                       2
  Testing                        1

Вот код, который я пробовал,

#include <stdio.h>
int main()
{
     int cCount, sCount, tCount;
     char name, chan, C, S, T, c, s, t;

     chan = " ";
     cCount = sCount = tCount = 0;

     FILE *cPtr;
     cPtr = fopen ("appointment.dat", "r");

     while (!feof(cPtr))
     {
          fscan (cPtr, "%s", &chan);

          if (chan == C)
               cCount++;

          else if (chan == S)
               sCount++;

          else if (chan == T)
               tCount++;
     }

     printf ("Appointment Type       Number of patients\n");
     printf ("Consulting                     %d        \n");
     printf ("Scanning                       %d        \n");
     printf ("Testing                        %d        \n");

     return 0;
}

I У меня проблемы с настройкой отображаемой части. Количество пациентов отображает некоторые адреса вместо количества пациентов.

Как изменить код для правильного подсчета пациентов?

1 Ответ

0 голосов
/ 24 апреля 2020

Вы попали в одну из первых ловушек, в которую попадают самые новые C программисты. Почему while (! Feof (file)) всегда неверно? При вызове fscan (cPtr, "%s", &chan); (который должен быть fscanf), для последней строки ввода, читаем успешно и EOF не установлено. Вы тестируете while (!feof(cPtr)) - и это НЕ. Вы снова наберете oop и достигнете fscan (cPtr, "%s", &chan);, который теперь не срабатывает из-за сбоя ввода и EOF возвращается - но вы слепо переходите к проверке if (chan), которая может дать сбой в этот момент или может показаться, что работает правильно (добавление дополнительного ошибочного счетчика к переменной, соответствующей тому, что было последним значением chan). 1

Вы также вызываете Неопределенное поведение при использовании printf, не предоставив аргумента для "%d" спецификатор преобразования , содержащийся в строке формата , например,

 printf ("Consulting                     %d        \n");

C11 Standard - 7.21.6.1 Функция fprintf (p2) (это объясняет вашу «Количество пациентов отображает некоторые адреса вместо количества пациентов.» )

Когда вы читаете строку ввода одновременно, используйте ориентированную на строку функция ввода, например fgets() или POSIX getline(), для чтения всей строки в массив достаточного размера, а затем использование sscanf() для разделения массива на необходимые значения, например,

#define MAXC 128        /* if you need a constant, #define one (or more) */
...
    char buf[MAXC], name[MAXC], type;
    ...
    while (fgets (buf, MAXC, fp)) {                     /* read each line into buf */
        if (sscanf (buf, "%s %c", name, &type) == 2) {  /* split buf into name, type */

Вы используете return самой функции чтения для управления продолжением чтения -l oop. Вы не можете правильно использовать любую функцию пользовательского ввода без Проверка return.

Теперь вы можете проверить type. Простой способ - использовать оператор switch() - хотя в последовательности операторов if() нет ничего плохого. Вы можете использовать switch(), подобный следующему:

            switch (type) {                             /* switch on type */
                case 'C': C++; break;
                case 'S': S++; break;
                case 'T': T++; break;
                default:
                    fprintf (stderr, "error: invalid type '%c'\n", type);
                    break;
            }

Полностью подставив его и разрешив передать имя файла в качестве первого аргумента программе (или прочитать из stdin по умолчанию, если имя файла отсутствует дано), вы можете сделать:

#include <stdio.h>

#define MAXC 128        /* if you need a constant, #define one (or more) */

int main (int argc, char **argv) {

    char buf[MAXC], name[MAXC], type;
    size_t C = 0, S = 0, T = 0;
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    while (fgets (buf, MAXC, fp)) {                     /* read each line into buf */
        if (sscanf (buf, "%s %c", name, &type) == 2) {  /* split buf into name, type */
            switch (type) {                             /* switch on type */
                case 'C': C++; break;
                case 'S': S++; break;
                case 'T': T++; break;
                default:
                    fprintf (stderr, "error: invalid type '%c'\n", type);
                    break;
            }
        }
    }
    if (fp != stdin)   /* close file if not stdin */
        fclose (fp);

    printf ("Appointment Type       Number of patients\n"   /* output results */
            "Consulting             %9zu\n"
            "Scanning               %9zu\n"
            "Testing                %9zu\n", C, S, T);
}

( note: вам нужен только один оператор printf для каждого непрерывного вывода. Компилятор C объединит все соседние строки, разделенные пробелами Например, "..." "..." в одну строку)

Пример использования / Вывод

Просто введите ваш ввод для программы на stdin с помощью bash heredo c, вы получите:

$ cat << eof | ./bin/appointments
> Dave C
> Ryan T
> Mary S
> George C
> Julian S
> eof
Appointment Type       Number of patients
Consulting                     2
Scanning                       2
Testing                        1

Чтение из файла

С вашими данными в файле dat/appointment_types.txt Например,

$ cat dat/appointment_types.txt
Dave C
Ryan T
Mary S
George C
Julian S

Ваше использование и вывод будет следующим:

$ ./bin/appointments dat/appointment_types.txt
Appointment Type       Number of patients
Consulting                     2
Scanning                       2
Testing                        1

Просмотрите все и дайте мне знать, если у вас есть дополнительные вопросы.

Сноски:

1. Стандарт C не определяет, что chan будет удерживать после сбоя ввода происходит. C11 Standard - 7.21.6.2 Функция fscanf (p9) Поведение просто не определено, поскольку chan является неопределенным в этой точке и используется, пока оно имеет неопределенное значение. Стандарт C11 - J.2 Неопределенное поведение "The value of an object with automatic storage duration is used while it is indeterminate (6.2.4, 6.7.9, 6.8)." и см. Обсуждение Неопределенное, неопределенное и определяемое реализацией поведение и Что такое неопределенное поведение в C ++? Чем он отличается от неопределенного поведения?

...