2017-10-10 90 views
0

好的,我知道代码可能很长,但我尽可能地尽量减少它。我想让代码工作,以便重新创建我的问题。我的问题是,当我尝试读取文本文件时,它不会读取所有项目。它似乎只读了最后几个。我可能无意中改变了一些东西,因为它以前工作得很好。当你在程序和注册项目,它计数项目就好了。但是,当您打开文件时,只是将项目保存在其中。它计数的项目数量少于实际文件中的项目数量,并且阵列全部错误。如果任何人都可以在我的代码中看到问题,那将非常感激。程序将无法正确读取文本文件

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

#define MAX 20 

struct items 
{ 
    int itemnumber; 
    char name[30]; 
    int balance; 
}; 

void open_file(FILE *enter_filename, char filename[], struct items aItems[], int *num_items) 
{ 
    int i=0; 

     printf("Choose filename (.txt).\n"); 
     scanf("%19s", filename); 
     enter_filename=fopen(filename, "r+"); 
     if(enter_filename) 
     { 
      while(!feof(enter_filename)) 
      { 
       for(i = 0; i < *num_items; i++) 
        { 
        fscanf(enter_filename, "Itemnumber: %d\n", &aItems[i].itemnumber); 
        fscanf(enter_filename, "Name: %s\n", aItems[i].name); 
        fscanf(enter_filename, "Balance: %d\n", &aItems[i].balance); 
        } 
       if(!feof(enter_filename)) 
       { 
        *num_items=*num_items + 1;  
       } 
      } 
      printf("\nNumber of items: %d \n",*num_items); 
      fclose(enter_filename); 
     } 
     else 
     { 
      printf("That file doesn't exist! Create a new one.\n"); 
      printf("What name do you want for your new file?\n"); 
      scanf("%19s", filename); 
      enter_filename=fopen(filename, "w+"); 
      printf("File is created!\n"); 
      *num_items = 0;     
      fclose(enter_filename); 
     } 
} 
void register_item(struct items *aItems, int *num_items) 
{ 
    int success=1; 
    if(*num_items < MAX) 
     { 
     while(1) 
     { 
      printf("Item number:\n");        
      scanf("%d", &aItems[*num_items].itemnumber); 
      for(int i=0; i < *num_items; i++) 
      { 
      if(aItems[*num_items].itemnumber == aItems[i].itemnumber) 
       { 
       printf("Item number already exists, choose a unique item number.\n"); 
       success=0; 
       break; 
       } 
      else 
       { 
       success=1; 
       } 
      } 
     if(success)break; 
     } 
     printf("Name:\n"); 
     scanf("%29s", aItems[*num_items].name); 
     strlwr(aItems[*num_items].name); 
     printf("Balance:\n"); 
     scanf("%d", &aItems[*num_items].balance); 
     *num_items+=1; 
     } 
} 
void print_item(struct items aItems[], int num_items) 
{ 
    int i; 
    for (i=0; i < num_items; i++) 
    { 
    printf("%d. Item number: %d Name: %s Balance: %d\n", i+1, aItems[i].itemnumber, aItems[i].name, aItems[i].balance);   
    } 
} 
void quit_program(char filename[], struct items aItems[], int *num_items) 
{ 
    FILE *fil; 
    fil=fopen(filename, "w+");            
    int i; 
    for(i = 0; i < *num_items; i++) 
     { 
     fprintf(fil, "Itemnumber: %d\n", aItems[i].itemnumber); 
     fprintf(fil, "Name: %s\n", aItems[i].name); 
     fprintf(fil, "Balance: %d\n\n", aItems[i].balance); 
     } 
    fclose(fil); 
} 
int main(void) 
{ 
    FILE *enter_filename; 
    struct items aItems[MAX]; 

    int menu, num_items=0; 
    char filename[20]; 

    open_file(enter_filename,filename, aItems, &num_items); 

    while(menu!=3) 
    { 
     printf("\n"); 
     printf("1. Register new items to inventory.\n"); 
     printf("2. Print all items from inventory.\n"); 
     printf("3. Quit\n"); 
     scanf("%d", &menu); 

     if(menu==1) 
     { 
      register_item(aItems, &num_items); 
     } 

     if(menu==2) 
     { 
      print_item(aItems, num_items); 
     } 

     if(menu==3) 
     { 
     quit_program(filename, aItems, &num_items); 
     } 
    } 
return 0; 
} 
+2

我不明白这可能是一个[mcve]读取文件的问题。也许从头创建一个?一般来说,我推荐阅读[如何调试小程序](https:// ericlippert。COM/2014/03/05 /如何调试的小程序/)。 –

+2

请参阅[为什么“while(!feof(file))”总是错误?](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong)。这是一个非常糟糕的模式。另外,请考虑显示它应该读取的部分文件。 – unwind

+0

如果我从这里删除更多的代码或尝试从头开始,它将是一个不同的程序。我只添加了运行程序所需的东西。 – Camel

回答

1

你的错误是在这里:

 while(!feof(enter_filename)) 
     { 
      for(i = 0; i < *num_items; i++) 
       { 
       fscanf(enter_filename, "Itemnumber: %d\n", &aItems[i].itemnumber); 
       fscanf(enter_filename, "Name: %s\n", aItems[i].name); 
       fscanf(enter_filename, "Balance: %d\n", &aItems[i].balance); 
       } 
      if(!feof(enter_filename)) 
      { 
       *num_items=*num_items + 1;  
      } 
     } 
在第一次通过你的循环

*num_items是零,所以核能研究所循环,它的实际读数将不会进入和aItems[i]将未初始化。然后你增加物品计数器。

在下一回合中,只会读取一个项目,即aItems[1],但会收到第一个项目的数据。您增加计数器。在第三遍中,您读取的是aItems[2],但立即覆盖它,因为内部循环会创建与数组中当前元素一样多的遍历。显然,这是错误的。

当您阅读文件时,您不知道有多少物品。因此,您必须阅读一个项目,测试它是否可以读取,然后相应地增加计数器。测试文件是否结束或者输入是否正确是通过fscanf的返回值完成的,该值返回已成功转换的项目数。

你的循环可以这样工作的:

 while (*num_items < MAX) { 
      struct items *p = &aItems[*num_items]; 

      if (fscanf(f, "Itemnumber: %d\n", &p->itemnumber) < 1 
      || fscanf(f, "Name: %s\n", p->name) < 1 
      || fscanf(f, "Balance: %d\n", &p->balance) < 1) { 
       break; 
      } 

      (*num_items)++; 
     } 

(我称为文件处理fenter_filename既是太长太误导)

其他注意事项:

  • 文件句柄和文件名是本地函数;它们不在外面使用,手柄可以正确打开和关闭。因此,你不应该将它们作为参数传递,而是将它们作为局部变量。
  • 变量menu未初始化,启动程序时可能为3。
+0

你完全解释了我的问题。你介意解释这个代码吗?我不太了解if语句<1 – Camel

+0

'fscanf'返回被转换的值的数量,或多或少地理解了格式字符串中的'%'序列的数量,特殊值'EOF'表示遇到文件的末尾。 'EOF'是负数,通常是-1。如果有任何数据线不能被读取,您将跳出循环。 –

+0

(通过读取函数的返回值控制文件输入是读取文件的首选方式;请参阅Serkan答案中的链接。在找到'EOF'后可以使用函数feof()和ferror()无论原因是读取错误还是文件实际结束。) –

0

在你open_file功能使用while(!feof(enter_filename))

这不是读取文件的一种可靠的方法,as it is stated in this question. 对于你的情况,你最终是什么,既然你在一个错误的while(!feof(enter_filename))回路设置num_items,你num_items持有一个错误的值,并将它传播通过你们的节目因为您几乎在任何地方都在使用它,特别是在再次写回文件时,这解释了缺失的行。一旦执行herehere中提到的方法之一,请使用您的调试器确保num_items与您的输入文件一致。