Daniel Garcia
Daniel Garcia

Reputation: 13

How do I read a binary file into a buffer and then set struct pointers at different points to initialize them?

I want to read a chunk of data from a binary file into a buffer and then place pointers at different locations in the buffer to store the structs in the buffer. However, I get the wrong data back when I try this method, possibly due to where I'm placing the pointers.

Note: readEntry and writeThis are just low level read() and write() with error trapping built in. readEntry terminates the program once it reaches the end of the file.

#define BUF    64

struct my_struct
{
    int num;
};

my_struct and definition of BUF

int i;
char buffer[BUF];
struct my_struct *m = (struct my_struct *) malloc(sizeof(struct my_struct));

for(i=0; i<4; i++)
{   
    m->num = i;
    printf("Initializing m->num to %d\n", m->num);
    writeThis(fd, &m, sizeof(struct my_struct));
}   

lseek(fd, 0, SEEK_SET);

while(1)
{   
    printf("Read\n");
    readEntry(fd, buffer, (sizeof(struct my_struct)*4));
    m = (struct my_struct *) buffer;
    printf("num = %d\n", m->num);
    m = (struct my_struct *) buffer+(sizeof(m));
    printf("num = %d\n", m->num);
    m = (struct my_struct *) buffer+((sizeof(m)*2));
    printf("num = %d\n", m->num);
    m = (struct my_struct *) buffer+((sizeof(m)*3));
    printf("num = %d\n", m->num);
}   
return 0;

writeThis()

void writeThis(int fd, void *buffer, int writeAmt)
{
    if (write(fd, buffer, writeAmt) != writeAmt)
    {
        fprintf(stderr, "Error writing\n");
        exit(-1);
    }
}

readEntry()

void readEntry(int fd, void *buffer, int writeAmt)
{
    if (read(fd, buffer, writeAmt) != writeAmt)
    {
        printf("Finished reading\n");
        free(buffer);
        exit(0);
    }
}

The return I get for the sizeof(struct my_struct) is 4

Output:

Initializing m->num to 0
Initializing m->num to 1
Initializing m->num to 2
Initializing m->num to 3
Read
num = 134524936
num = -1208081680
num = -1209552416
num = 1111804576
Read
Finished reading

hexdump

00000000  10 b4 04 08 10 b4 04 08  10 b4 04 08 10 b4 04 08  |................|
00000010

Upvotes: 1

Views: 122

Answers (1)

chux
chux

Reputation: 153498

Some cleaned-up untested code - see comment for fixes to the problems. The 2 big ones are & when not needed and pointer arithmetic.

#define BUF    64

struct my_struct {
    int num;
};

int i;

// Suggest `malloc()` rather than `char buffer[BUF]`.
// The issues is _alignment_, perhaps that is new for you.
char *buffer = malloc(BUF);

// Cast not needed.  Better to use size of variable, than sizeof type.
// Think how easy this is to maintain code should `m` take on a new type.
// struct my_struct *m = (struct my_struct *) malloc(sizeof(struct my_struct));
struct my_struct *m = malloc(sizeof *m);

for(i=0; i<4; i++) {   
    m->num = i;
    printf("Initializing m->num to %d\n", m->num);
    // & not needed here.  `m` is the pointer to the place to read data
    // writeThis(fd, &m, sizeof(struct my_struct));
    // Use size of variable
    writeThis(fd, m, sizeof *m);
}   

lseek(fd, 0, SEEK_SET);

while(1)
{   
    printf("Read\n");
    // Again, use sizeof the variable, rather than size of type
    //readEntry(fd, buffer, (sizeof(struct my_struct)*4));
    readEntry(fd, buffer, sizeof *m *4);
    m = (struct my_struct *) buffer;
    printf("num = %d\n", m->num);

    // do not cast and then add to char *
    // add and then cast
    // m = (struct my_struct *) buffer+(sizeof(m));
    m = (struct my_struct *) (buffer+(sizeof(*m));
    // OR, add after the cast, but only add 1
    m = (struct my_struct *) buffer + 1;

    printf("num = %d\n", m->num);
    m = (struct my_struct *) buffer+2;
    printf("num = %d\n", m->num);
    m = (struct my_struct *) buffer+3;
    printf("num = %d\n", m->num);

    // You could have an infinite loop here, need a reason to exit
}  
free(buf);

return 0;

Robust code would check the return results from malloc() before using them

Upvotes: 1

Related Questions