如何使用fscanf()在C中逐行读取某些文件而又不产生幻像行?

问题描述 投票:0回答:1

我的代码中有一个函数,它逐行读取一些文件并从中创建结构。一位教授对我说,可能有问题,并提到了幻影线。有人可以看到我的功能并向我解释问题出在哪里吗?

这是我的代码:

void readComponentList(ComponentList *cl, char *fileName)
{
   FILE *file = fopen(fileName, "r");
   if (file == NULL) { perror(fileName);  exit(1); } // If the file doesn't exist, the program termitates with exit code 1
   int r;
   Component *c = newComponent(cl);
   // Creates useful component c by inserting line informations as arguments in the structure
   r = fscanf(file, "%24s %24s %24s %d %lf", c->type, c->model, c->unit, &(c->weight), &(c->price));
   while (r != EOF) // Doing the same thing for the rest of the lines
   {
      c = newComponent(cl);
      r = fscanf(file, "%24s %24s %24s %d %lf", c->type, c->model, c->unit, &(c->weight), &(c->price);
      // Since EOF only occurs after an unsuccessful read attempt, an additional "phantom line" with undefined content is read in here, which could lead to crashes.

   }
   fclose(file);
}

这是我正在阅读的文件示例:

Motor M5x40 Stk 5 0.05
Elevator M5x60 Stk 6 0.05
ACM L-H-100 Stk 1250 530
SSM L-100 Stk 0 0
ElevatorW W3 Stk 0 0
Metal- kg 1000 344200

Component和ComponentList结构:

typedef struct
{
   char     type[25];
   char     model[25];
   char     unit[25];
   int      weight;
   double   price;
   StepList *construction_steps;
} Component;

typedef struct
{
   Component **components;
   int count;
   int allocated;
} ComponentList;
c scanf file-read
1个回答
0
投票

从发布的代码尚不清楚,但我认为这行

Component *c = newComponent(cl);

将1)创建一个新的Component元素,并将其2)插入到列表cl

因此,当您执行此操作之前调用fscanf时,即使fscanf失败,元素也已插入**。因此,您将在列表中得到一个“空”元素(又称为幻影元素)。

[为避免需要移动以下行:Component *c = newComponent(cl);,以便仅在成功scanf之后才调用它。

也许像:

Component tmp;  // Scan into a local tmp variable
while (1)
{
   r = fscanf(file, "%24s %24s %24s %d %lf", 
                    tmp.type, tmp.model, tmp.unit, &tmp.weight, &tmp.price;

   if (r == EOF) break;

   if (r == 5)
   {
       // A complete struct was read so put it into the list
       c = newComponent(cl);
       *c = tmp;   // Copy the tmp struct into the new element in the list
   }
   else
   {
       // Didn't get the expected number of vars scanned.
       // Add error handling ....
   }
}

编辑

由于OP关注第Component tmp;行,因此这是另一种方法:

char     type[25];
char     model[25];
char     unit[25];
int      weight;
double   price;

while (1)
{
   r = fscanf(file, "%24s %24s %24s %d %lf", 
                    type, model, unit, &weight, &price;

   if (r == EOF) break;

   if (r == 5)
   {
       // A complete struct was read so put it into the list
       c = newComponent(cl);
       strcpy(c->type, type);
       strcpy(c->model, model);
       strcpy(c->unit, unit);
       c->weight = weight;
       c->price = price;
   }
   else
   {
       // Didn't get the expected number of vars scanned.
       // Add error handling ....
   }
}
© www.soinside.com 2019 - 2024. All rights reserved.