我正在尝试从文件中读取患者信息,将文件中的数据插入到结构的字段中,然后将节点插入到链接列表中,直到我达到EOF。我遇到的问题是当我到达EOF时试图终止我的while循环。我用fscanf读取文件的每一行,另一个用来检查文件的结尾。拥有2个fscanf会导致每次都有一个新行,并跳过我的一半数据。什么是在while循环中检查EOF的更好方法? 我的文本文档中的信息格式如此。除了它们不是每个患者之间的换行符。为了便于阅读,我在这篇文章中做了这个。
Sophia Jackson 1234 141.0 1.1
Emma Aiden 5432 142.0 1.2Olivia Lucas 5685 143.0 1.3
Ava Liam 5672 144.0 1.4
Mia Noah 3467 145.0 1.5
Isabella Ethan 8654 146.0 1.6
Riley Mason 2567 147.0 1.7
Aria Caden 6794 148.0 1.8
Zoe Oliver 3467 149.0 1.9
fp = fopen("info.txt","r");
if(fp == NULL){
printf("ERROR File Doesn't exist\n");
}
while(1){
newptr = (node*)malloc(sizeof(node));
newptr->back = NULL;
newptr->next = NULL;
newptr->phgnum = 0;
newptr->pid = 0;
newptr->pwt = 0;
fscanf(fp,"%s %s %i %f %f",newptr->pfn,newptr->pln,&newptr->pid,&newptr->pwt,&newptr->phgnum);
printf("First Name: %s\n",newptr->pfn);
printf("Last Name: %s\n",newptr->pln);
printf("PID: %i\n",newptr->pid);
printf("Weight: %f\n",newptr->pwt);
printf("HG1AC: %f\n",newptr->phgnum);
(insert node into linked list)
// test for EOF
if( 5!= fscanf(fp,"%s %s %i %f %f",newptr->pfn,newptr->pln,&newptr->pid,&newptr->pwt,&newptr->phgnum))
break;
答案 0 :(得分:2)
当您阅读格式化数据时,您希望基于成功读取数据单元(此处为一行)来控制循环。这可以确保您在验证读取后只尝试处理信息。虽然通常最好使用fgets
然后调用sscanf
,但在从格式化文件中读取时,它最终会等同于您的fscanf
调用。唯一的区别是您失去了独立验证读取和解析的能力。 (这是否重要取决于情况)
对于您的阅读,在分配节点之前,通过将值读入临时结构可以更好地服务。在读取之前不需要分配,允许您在致电malloc
之前验证您的读数。根据您的需要,有不同的方法可以做到这一点,但一般方法是:
#include <stdio.h>
#include <stdlib.h>
#define MAXNAME 16 /* size as appropriate - or dynamically allocate */
typedef struct { /* declare struct as required */
char pfn[MAXNAME],
pln[MAXNAME];
float pwt,
phgnum;
int pid;
} node_t;
int main (int argc, char **argv) {
size_t npt = 0; /* number of patients */
node_t tmp = { .pfn = "" }; /* temp struct for read */
/* read from filename given as 1st argument (or stdin by defaut) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
/* while there is a good read of patient data */
while (fscanf (fp, "%15s %15s %d %f %f", tmp.pfn, tmp.pln, &tmp.pid,
&tmp.pwt, &tmp.phgnum) == 5) {
node_t *newptr = malloc (sizeof *newptr); /* allocate node */
if (!newptr) { /* validate allocation */
perror ("malloc-newptr");
break;
}
*newptr = tmp; /* assign tmp data to node */
/* add to linked list -- here */
printf ("%-16s %-16s %5d %6.2f %6.2f\n", newptr->pfn, newptr->pln,
newptr->pid, newptr->pwt, newptr->phgnum);
npt++; /* increment patient count */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
/* don't forget to free list */
return 0;
}
(注意:数据只是在上面输出,您只需将其添加到列表中并删除输出(或将其包装在#ifdef DEBUG ... #endif
中,使其以DEBUG
是否已定义为条件) )
示例输入文件
$cat dat/patients.txt
Sophia Jackson 1234 141.0 1.1
Emma Aiden 5432 142.0 1.2
Olivia Lucas 5685 143.0 1.3
Ava Liam 5672 144.0 1.4
Mia Noah 3467 145.0 1.5
Isabella Ethan 8654 146.0 1.6
Riley Mason 2567 147.0 1.7
Aria Caden 6794 148.0 1.8
Zoe Oliver 3467 149.0 1.9
示例使用/输出
$ ./bin/patient_read <dat/patients.txt
Sophia Jackson 1234 141.00 1.10
Emma Aiden 5432 142.00 1.20
Olivia Lucas 5685 143.00 1.30
Ava Liam 5672 144.00 1.40
Mia Noah 3467 145.00 1.50
Isabella Ethan 8654 146.00 1.60
Riley Mason 2567 147.00 1.70
Aria Caden 6794 148.00 1.80
Zoe Oliver 3467 149.00 1.90
仔细看看,如果您有任何问题,请告诉我。
答案 1 :(得分:1)
fscanf()
的返回值在文件结束时为EOF,在早期匹配失败时为0。否则,返回成功匹配的输入项的数量。因此,您可以将此作为while循环本身的测试条件:
while (fscanf(fp, "%s %s %i %f %f", ...) == 5) {
// ...
}
例如,请考虑以下最小程序:
#include <stdio.h>
int main(void) {
char fname[50], lname[50];
int id;
float weight, hgnum;
FILE *fp = fopen("info.txt", "r");
if (fp == NULL) {
perror("Error: Failed to open file.");
return 1;
}
while (fscanf(fp, "%49s %49s %i %f %f", fname, lname, &id, &weight, &hgnum) == 5) {
printf("First Name: %s\n", fname);
printf("Last Name: %s\n", lname);
printf("PID: %i\n", id);
printf("Weight: %.1f\n", weight);
printf("HG1AC: %.1f\n\n", hgnum);
}
return 0;
}
这将打印您的文本文件示例,如下所示:
First Name: Sophia
Last Name: Jackson
PID: 1234
Weight: 141.0
HG1AC: 1.1
First Name: Emma
Last Name: Aiden
PID: 5432
Weight: 142.0
HG1AC: 1.2
First Name: Olivia
Last Name: Lucas
PID: 5685
Weight: 143.0
HG1AC: 1.3
First Name: Ava
Last Name: Liam
PID: 5672
Weight: 144.0
HG1AC: 1.4
First Name: Mia
Last Name: Noah
PID: 3467
Weight: 145.0
HG1AC: 1.5
First Name: Isabella
Last Name: Ethan
PID: 8654
Weight: 146.0
HG1AC: 1.6
First Name: Riley
Last Name: Mason
PID: 2567
Weight: 147.0
HG1AC: 1.7
First Name: Aria
Last Name: Caden
PID: 6794
Weight: 148.0
HG1AC: 1.8
First Name: Zoe
Last Name: Oliver
PID: 3467
Weight: 149.0
HG1AC: 1.9