[英]How to display the count of records in a file?
The scenario goes like this,剧情是这样的,
A medical center needs to store appointment details in a text file called appointment.dat.医疗中心需要将预约详细信息存储在名为约会.dat 的文本文件中。
It includes the Patient name and the Appointment type.它包括患者姓名和约会类型。 The appointment types can either be 'Consulting' , 'Scanning' or 'Testing' .
约会类型可以是“咨询” 、 “扫描”或“测试” 。 Only the first letter is stored in the file.
只有第一个字母存储在文件中。
The requirement is to,要求是,
appointment.dat
fileappointment.dat
文件appointment.dat
file under the given sample format.appointment.dat
文件中。 Dave C
Ryan T
Mary S
George C
Julian S
appointment.dat
file and calculate and display the Number of Patients under the given format.appointment.dat
文件并计算并显示给定格式下的患者人数。 Appointment Type Number of patients
Consulting 2
Scanning 2
Testing 1
Here's the code I tried,这是我试过的代码,
#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'm having trouble getting the displaying part right.我无法正确显示显示部分。 The Number of Patients displays some addresses instead of the patient count.
患者人数显示一些地址而不是患者人数。
How do I modify the code to get the patient count right?如何修改代码以正确计算患者人数?
You have fallen into one of the first pitfalls most new C-programmers fall into.您已经陷入了大多数 C 程序员新手最容易陷入的陷阱之一。 Why is while (?feof (file) ) always wrong?
为什么 while (?feof (file) ) 总是错误的? On your call to
fscan (cPtr, "%s", &chan);
在您调用
fscan (cPtr, "%s", &chan);
(which should be fscanf
), for the last line of input, the read succeeds and EOF
is not set. (应该是
fscanf
),对于输入的最后一行,读取成功并且没有设置EOF
。 You test while (!feof(cPtr))
-- and it's NOT.你测试
while (!feof(cPtr))
- 它不是。 You loop again and reach fscan (cPtr, "%s", &chan);
您再次循环并到达
fscan (cPtr, "%s", &chan);
which now fails due to an input-failure and EOF
is returned -- but you blindly proceed to check if (chan)
which may fail at this point or may appear to work correctly (adding an additional erroneous count to the variable corresponding to whatever the last value of chan
was).现在由于输入失败而失败并返回
EOF
- 但是您盲目地继续检查if (chan)
这可能在这一点上失败或可能看起来正常工作(向对应于任何内容的变量添加额外的错误计数chan
的最后一个值是)。 1 1
You further invoke Undefined Behavior in your use of printf
by failing to provide any argument for the "%d"
conversion specifier contained in the format string , eg您在使用
printf
通过未能为格式字符串中包含的"%d"
转换说明符提供任何参数来进一步调用未定义行为,例如
printf ("Consulting %d \n");
C11 Standard - 7.21.6.1 The fprintf function(p2) (this explains your "The Number of Patients displays some addresses instead of the patient count." ) C11 标准 - 7.21.6.1 fprintf 函数(p2) (这解释了您的“患者人数显示一些地址而不是患者人数。” )
When you are reading a line-of-input at a time, use a line-oriented input function like fgets()
or POSIX getline()
to read a complete line into a sufficiently sized array, and then use sscanf()
to separate the array into the needed values, eg当您一次读取输入行时,使用面向行的输入 function (如
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 */
You use the return of the read function itself to control the continuation of the read-loop.您使用读取 function 本身的返回来控制读取循环的继续。 You cannot use any user-input function correctly without Checking the
return
.如果不检查
return
,您将无法正确使用任何用户输入 function 。
Now you can check the type
.现在您可以检查
type
。 A simple way is to use a switch()
statement -- though there is nothing wrong with a sequence of if()
statements.一种简单的方法是使用
switch()
语句——尽管if()
语句序列没有任何问题。 You can use a switch()
similar to:您可以使用类似于以下内容的
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;
}
Putting it altogether, and allowing the filename to be passed as the first argument to the program (or read from stdin
by default if no filename is given), you could do:总而言之,并允许将文件名作为第一个参数传递给程序(如果没有给出文件名,则默认从
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: you only need one printf
statement for each contiguous output. The C compiler will concatenate all adjacent whitespace separated strings, eg "..."
"..."
into a single string) (注意:对于每个连续的 output,您只需要一个
printf
语句。C 编译器会将所有相邻的空格分隔字符串,例如"..."
"..."
Example Use/Output示例使用/输出
Simply providing your input to the program on stdin
using a bash heredoc , you would get:只需使用 bash heredoc将您的输入提供给
stdin
上的程序,您将获得:
$ 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
Reading From A File从文件中读取
With your data in the file dat/appointment_types.txt
, eg使用文件
dat/appointment_types.txt
中的数据,例如
$ cat dat/appointment_types.txt
Dave C
Ryan T
Mary S
George C
Julian S
Your use and output would be:您的使用和 output 将是:
$ ./bin/appointments dat/appointment_types.txt
Appointment Type Number of patients
Consulting 2
Scanning 2
Testing 1
Look things over and let me know if you have further questions.如果您还有其他问题,请仔细查看并告诉我。
Footnotes:脚注:
1. The C-Standard does not define what chan
will hold after an input-failure occurs. 1. C-Standard 没有定义输入失败发生后
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 标准 - 7.21.6.2 fscanf 函数(p9)行为只是未定义,因为此时
chan
是不确定的,并且在它具有不确定值时使用。 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)."
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)."
and see discussion Undefined, unspecified and implementation-defined behavior and What is indeterminate behavior in C++?并查看讨论未定义、未指定和实现定义的行为以及C++ 中的不确定行为是什么? How is it different from undefined behavior?
它与未定义的行为有何不同?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.