程序无法从文本文件中正确读取

时间:2017-10-10 12:41:23

标签: c arrays file text struct

好的,我知道代码可能很长但我尽可能地将其最小化。我希望代码能够工作,这样你就可以重新创建我的问题了。我的问题是,当我尝试阅读文本文件时,它并没有读取所有项目。它似乎只读了最后几个。我可能会在没有注意的情况下意外地改变了一些东西,因为之前它工作得很好。当您进入程序并注册项目时,它会对项目进行计数。但是当你打开文件时,你刚刚保存了你的项目。它计算的项目数量少于实际文件中的数量,并且数组完全错误。如果有人能在我的代码中看到问题,那将非常感激。

#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 个答案:

答案 0 :(得分: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为零,因此不会输入执行实际读数的iner循环,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。

答案 1 :(得分:0)

open_file功能中,您使用while(!feof(enter_filename))

这不是一种可靠的文件阅读方式,as it is stated in this question. 对于您的情况,您最终的结果是,因为您在错误的num_items循环中设置了while(!feof(enter_filename)),您的num_items包含错误的值,并且它会通过您的程序逻辑传播,因为您正在使用它几乎无处不在,特别是当再次写回文件时,这解释了缺失的线条。实施herehere中提到的方法之一后,请使用调试器确保num_items与输入文件一致。