1

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
  • You are leaking memory and causing undefined behavior by accessing an object of type `char` though an expression not of type `char` or character type. – EOF Apr 04 '16 at 21:01
  • Recommend using `char buffer = malloc(BUF);` to insure it and `m` are aligned the same. - or use some other approach to insure alignment. As it is now `m = (struct my_struct *) buffer;` is likely UB. – chux - Reinstate Monica Apr 04 '16 at 21:01
  • BTW: insure `BUF >= sizeof(struct my_struct)*4`. – chux - Reinstate Monica Apr 04 '16 at 21:04
  • Hmmm perhaps `writeThis(fd, &m, sizeof(struct my_struct));` --> `writeThis(fd, m, sizeof(struct my_struct));` (no &) – chux - Reinstate Monica Apr 04 '16 at 21:06
  • Please provide `readEntry()` and `writeThis()` code. @chux may be right, but it is hard to tell without seeing the code. Have you checked the contents of the file manually? What does `hexdump -C ` yield? – Honza Remeš Apr 04 '16 at 21:25
  • Also, [don't cast `malloc()` return value](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). – Honza Remeš Apr 04 '16 at 21:27
  • Thanks for the helpful responses everyone! @chux, whenever I try to initialize `char buffer = malloc(BUF);` I get a warning from compile and a seg fault at runtime. And writing the binary file directly into the struct defeats the purpose of what I'm trying to do. @Honza Remeš I tried just using the raw malloc() result, and that did change the result, but didn't give the desired data back. – Daniel Garcia Apr 04 '16 at 22:26
  • My typo error: `char buffer[BUF];` --> `char *buffer = malloc(BUF);` (forgot *) – chux - Reinstate Monica Apr 04 '16 at 22:29

1 Answers1

1

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

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • THANKS! That did the trick! But why did just adding one at a time to the buffer work? Does it not always write the sizeof *m bytes to the buffer? – Daniel Garcia Apr 04 '16 at 22:50
  • @OP `m = (struct my_struct *) buffer+(sizeof(m));` is missing a `(`. – chux - Reinstate Monica Apr 04 '16 at 22:56
  • @OP `(struct my_struct *) (buffer+(sizeof(*m))` adds "the size of what `m` points to" times `sizeof char` to a `char *` . `m = (struct my_struct *) buffer + 1;` adds "1" times `sizeof struct my_struct` to a `struct my_struct *`. Research pointer arithmetic. – chux - Reinstate Monica Apr 04 '16 at 22:59