Reputation: 37
Ok, I know the code might be long but I minimized it as much as I could. I wanted the code to work so you could recreate my problem. My problem is that when I try to read a text file, it doesn't read all of the items. It seems to read only the last few. I might've accidentally changed something without noticing because it worked just fine before. When you're in the program and registering items, it counts the items just fine. But when you open the file you just saved your items in. The number of items it counts is less than what's in the actual file and the arrays get all wrong. If anyone can see the problem in my code, that would be very appreciated.
#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;
}
Upvotes: 0
Views: 987
Reputation: 29136
Your error is here:
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;
}
}
in the first pass through your loop, *num_items
is zero, so the iner loop that does the actual reading will not be entered and aItems[i]
will be uninitialised. You then increase the item counter.
In the next pass, exactly one item, namely aItems[1]
will be read, but it will receive the data of the first item.You increase the counter. In the third pass, you read aItems[2]
, but immediately overwrite it, because your inner loop makes as many passes as there are currently elements in the array. Clearly, that's wrong.
When you read the file, you don't know how many items there are. Therefore, you must read an item, test whether it could be read and then increase the counter accordingly. Testing whether the file has ended or whether the input was correct is done via the return value of fscanf
,which returns the number ofitems successfully converted.
Your loop could work like this:
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)++;
}
(I've called the file handle f
: enter_filename
is both too long and too misleading.)
Other things to note:
menu
is uninitialised and may well be 3 when you start the program.Upvotes: 1
Reputation: 693
In your open_file
function you use while(!feof(enter_filename))
.
This is not a reliable way of reading a file, as it is stated in this question.
For your case, what you end up is that since you set num_items
in a faulty while(!feof(enter_filename))
loop, your num_items
holds a wrong value, and it propagates through your program logic because you are using it almost everywhere, especially when writing back to the file again, which explains the missing lines. Once you implement one of the methods mentioned in here or here, use your debugger to ensure that num_items
are consistent with your input file.
Upvotes: 0