karoma
karoma

Reputation: 1558

Reading unknown number of structs from file - C

I'm having a bit of trouble getting my program to read in data from a file. The issue is that the file is currently empty. Each time the program is run, a single array of books[] will be populated and written to the file later on in the code. While I'm sure it will work when all 10 structs are in the file, at the moment it's crashing since the file is empty and it's trying to read in 10 structs.

Is there a way to read in an unknown number of structs (up to 10) from the file?

struct stock
{
    char name[31];
    int stock;
};

int main (void)
{
    stock books[10];

    FILE *fptr;
    fptr = fopen("stock.dat", "rb");
    fread(books, sizeof(struct stock), 10, fptr);

    fclose (fptr);
}

Upvotes: 0

Views: 3365

Answers (6)

paxdiablo
paxdiablo

Reputation: 882136

Crashing? Not those statements, I hope, unless the file's not there at all. It may be crashing if you assume you have ten valid items in your array, since the name fields probably won't be valid C strings.

The way you figure out how many you actually read is with:

num = fread(books, sizeof(struct stock), 10, fptr);

although I would prefer:

num = fread (book, sizeof(*book), sizeof(book) / sizeof(*book), fptr);

since that means you don't have to change lots of code in the event the type name or array size changes.

If it's possible the the file doesn't even open, you need to check the fopen return value as well. Complete code would look something like:

#include <stdio.h>

typedef struct {
    char name[31];
    int stock;
} tStock;

int main (void) {
    tStock book[10];
    size_t num, i;

    FILE *fptr = fopen ("stock.dat", "rb");
    if (fptr == NULL) {
        num = 0;
    } else {
        num = fread (book, sizeof(*book), sizeof(book) / sizeof(*book), fptr);
        fclose (fptr);
    }

    printf ("Read %d items\n", num);
    for (i = 0; i < num; i++) {
        printf ("   Item %d is %s, %d\n", book[i].name, book[i].stock);
    }

    return 0;
}

Upvotes: 1

Israel Unterman
Israel Unterman

Reputation: 13510

I'm not sure, but fread() is not supposed to crash, but to return the number of items read, which is 0 in this case. Also I don't exactly understand how the line stock books[10]; compiles, it should be struct stock books[10];.

I would suggest two things: 1. replace to struct stock books[10]; 2. An important thing to do is check that fptr is not NULL. Perhaps it couldn't open the file (maybe not in same directory or doesn'e exist yet), which results in a NULL fptr, and using it in fread would crash the app.

Upvotes: 0

Lundin
Lundin

Reputation: 214475

fptr = fopen("stock.dat", "rb");
if(fptr == NULL)
{
  // error
}
else
{
  for(int i=0; i<10 && !feof(fptr); i++)
  {
    fread(&books[i], sizeof(struct stock), 1, fptr);
  }
  fclose(fptr);
}

Upvotes: 0

Ed Heal
Ed Heal

Reputation: 60017

The code looks fine (have not give it a go though). See fread man page - it returns the number of items read.

Upvotes: 0

perreal
perreal

Reputation: 98088

If you know the maximum possible number of structures in the file and can afford to have them all in memory:

int main (void)
{
    #define MAX_BOOKS 10
    stock books[MAX_BOOKS];
    size_t cnt_books = 0;
    FILE *fptr;
    fptr = fopen("stock.dat", "rb");
    cnt_books = fread(books, sizeof(struct stock), MAX_BOOKS, fptr);
    fclose (fptr);
    return 0;
}

otherwise loop and read in chunks:

    while (cnt_books = fread(books, sizeof(struct stock), MAX_BOOKS, fptr)) {
      /* ... */
    }

Upvotes: 2

cnicutar
cnicutar

Reputation: 182674

Yes, you can do it:

  • You need to check the value returned by fopen to make sure the file exists
  • You need to check the number of items read - the size_t value returned by fread

Upvotes: 2

Related Questions