如何显示文件中的记录数?

How to display the count of records in a file?

剧情是这样的,

医疗中心需要将预约详细信息存储在名为 appointment.dat.

的文本文件中

它包括患者姓名预约类型。预约类型可以是'Consulting''Scanning''Testing'。只有第一个字母存储在文件中。

要求是,

  1. 创建 appointment.dat 文件
  2. 通过键盘输入获取5个患者的详细信息,并以给定的样本格式将数据写入appointment.dat文件。
  Dave                C
  Ryan                T
  Mary                S
  George              C
  Julian              S
  1. 读取 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;
}

我无法正确显示显示部分。患者人数显示一些地址而不是患者人数。

如何修改代码以使患者计数正确?

您已经掉进了大多数新 C 程序员掉入的第一个陷阱中。 Why is while ( !feof (file) ) always wrong? 在您调用 fscan (cPtr, "%s", &chan);(应该是 fscanf)时,对于输入的最后一行,读取成功并且未设置 EOF。您测试了 while (!feof(cPtr)) —— 但事实并非如此。你再次循环并到达 fscan (cPtr, "%s", &chan); 现在由于 输入失败 而失败并且 EOF 被 returned - 但你盲目地继续检查if (chan) 此时可能会失败,或者看起来可以正常工作(向对应于 chan 的最后一个值的变量添加额外的错误计数)。 1

您在使用 printf 时未为 "%d" 转换说明符 提供任何参数,从而进一步调用了 未定义行为 =97=] 包含在 格式字符串 中,例如

 printf ("Consulting                     %d        \n");

C11 Standard - 7.21.6.1 The fprintf function(p2)(这解释了你的 "The Number of Patients displays some addresses instead of the patient count."

当您一次读取一行输入时,使用面向行的输入函数,如fgets()或POSIXgetline() 将完整的一行读入一个足够大的数组,然后使用 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来控制读取循环的继续。如果不检查 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);
}

(注意:每个连续输出只需要一个 printf 语句。C 编译器将连接所有相邻的空格分隔的字符串,例如 "..." "..." 成一个字符串)

例子Use/Output

只需使用 bash heredocstdin 上的程序提供输入,您将得到:

$ 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 The fscanf function(p9) The behavior is simply undefined because chan is indeterminate at this point and used while it has an indeterminate value. C11 Standard - J.2 Undefined Behavior "The value of an object with automatic storage duration is used while it is indeterminate (6.2.4, 6.7.9, 6.8)." and see discussion Undefined, unspecified and implementation-defined behavior and What is indeterminate behavior in C++ ? How is it different from undefined behavior?