2

Lets say i used the fread function to read data from a file to a struct. How exactly is data read to the struct? Lets say my struct has the following:

Int x;
Char c;

Will the first 4 bytes read go into x and the next byte go into c? And if i read in more bytes than the elements in my struct can hold what's gonna happen?

3
  • You should read each data element separately and assign it to the data elements of your struct. Reading it directly into the struct will cause problems due to allignment. Commented Nov 2, 2019 at 11:35
  • 1
    What are Int and Char? Did you mean int and char? Commented Nov 2, 2019 at 12:18
  • Yeah int and char Commented Nov 3, 2019 at 7:01

3 Answers 3

3

fread reads data byte-for-byte from a file (stream) into memory. Therefore, if what you're trying to read is a struct, the byte layout of the struct in the file must exactly match the layout your compiler has chosen for the struct in memory.

So the question of "How does fread read from a file?" really boils down to, "How does the compiler lay out structs in memory?"

And the answer to that question is, it's partly determined by the rules of the C language, and it's partly up to the compiler.

So if you want to read structures from a file, you have three choices:

  1. Learn everything you can about the C rules for laying out structures in memory, and the choices compilers can make in interpreting these rules. Keep all these rules in mind as you design your structures and your data file formats. (This is not an impossible task. Many programmers take this approach to file i/o all the time.)

  2. Don't worry about the layout too much. Define your structures, and write them out to files using fwrite. Then the files are automatically readable using fread -- at least, as long as the program doing the reading is running on the same kind of machine, and was compiled by the same compiler using the same settings. (This, too, is a popular strategy, and works much of the time.)

  3. Don't use fread to read structures form a file. (And although it sounds defeatist, this is my own preferred argument.)

There's much, much more that could be said abut this question. If you choose approach 1, as I've already said, you're going to have to learn everything you can about the C rules for laying out structures in memory, and the choices compilers can make in interpreting these rules. If you choose approach 3, you have to learn some decent techniques for doing so without using fwrite and fread. But I'm not going to launch into long explanations of either of those topics here. I'm sure someone else will post some links, or you could start with Chapter 17 of these C programming notes.

Sign up to request clarification or add additional context in comments.

Comments

3

Will the first 4 bytes read go into x and the next byte go into c?

Yes, unless your compiler has extremely strange padding rules (e.g. every member must be 8 byte aligned). And assuming Int is 4 bytes and Char is 1 byte.

And if i read in more bytes than the elements in my struct can hold what's gonna happen?

That's undefined behavior, unless perhaps the over-long write is not more than sizeof(YourStruct) in which case you'll only be writing to the padding bytes (which on a lot of platforms will be 3 bytes after the char).

Comments

0

If anyone needs an example of how to do this

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

typedef struct {
    int x;
    char c;
} Data;

int main(void) {
    FILE* fp;

    // open the file in READ BYTES mode and check if the resulting pointer is NULL
    if ((fp = fopen("ztest.zf", "rb")) == NULL) {
        printf("Unable to open file\n");
        return 1;
    }

    Data* rdata = malloc(sizeof(Data));
    if (rdata == NULL) {
        printf("Error allocating memory\n");
        goto quit_err;
    }

    // use "rdata" pointer to read '1' byte at a time, with a limit of "sizeof(Data)", using the "fp" file pointer
    unsigned long rres = fread(rdata, 1, sizeof(Data), fp);
    // fread() will return the number of bytes read so we check if it read the correct amount
    if (rres != sizeof(Data)) {
        printf("Error reading data\n");
        goto quit_err;
    }

    // *rdata '*' is used to dereference the pointer because sizeof() will not read the pointer
    printf("Size = %lu , Read = %lu\n", sizeof(*rdata), rres);

    // check the data read
    printf("Data {\n  x: %c,\n  c: %d\n}\n", rdata->x, rdata->c);

    // free the data once you're done using it
    free(rdata);

    // close the file
    fclose(fp);

    return 0;
// goto label to close the file and exit with error code 1
// this will not be reached by the program because of the "return 0" statement above
// the only way this executes, is if we use "goto" when we find errors
quit_err:
    fclose(fp);
    return 1;
}

Keep in mind that "rb" expects a binary file. You will need to use "r" for text files

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.