2017-10-10 79 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與您的輸入文件一致。