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
8
  • 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. Commented Apr 4, 2016 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. Commented Apr 4, 2016 at 21:01
  • BTW: insure BUF >= sizeof(struct my_struct)*4. Commented Apr 4, 2016 at 21:04
  • Hmmm perhaps writeThis(fd, &m, sizeof(struct my_struct)); --> writeThis(fd, m, sizeof(struct my_struct)); (no &) Commented Apr 4, 2016 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 <thatfile> yield? Commented Apr 4, 2016 at 21:25

1 Answer 1

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

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

3 Comments

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?
@OP m = (struct my_struct *) buffer+(sizeof(m)); is missing a (.
@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.

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.