stdcerr
stdcerr

Reputation: 15658

how to write binary copy of structure array to file

I would like to write a binary image of a structure array to a binary file. I have tried this so far:

#include <stdio.h>
#include <string.h>
#define NUM 256

const char *fname="binary.bin";


typedef struct foo_s {
    int intA;
    int intB;
    char string[20];
}foo_t;



void main (void)
{
    foo_t bar[NUM];

    bar[0].intA = 10;
    bar[0].intB = 999;
    strcpy(bar[0].string,"Hello World!");

    Save(bar);
    printf("%s written succesfully!\n",fname);
}

int Save(foo_t* pData)
{
    FILE *pFile;
    int ptr = 0;
    int itr = 0;

    pFile = fopen(fname, "w");
    if (pFile == NULL) {
        printf("couldn't open %s\n", fname);
        return;
    }
    for (itr = 0; itr<NUM; itr++) {
        for (ptr=0; ptr<sizeof(foo_t); ptr++)
        {
            fputc((unsigned char)*((&pData[itr])+ptr), pFile);
        }
        fclose(pFile);
    }  
}

but the compiler is saying aggregate value used where an integer was expected fputc((unsigned char)*((&pData[itr])+ptr), pFile); and I don't quite understand why, what am I doing wrong?

Thanks!

Upvotes: 1

Views: 196

Answers (4)

chux
chux

Reputation: 154169

  1. Ensure file is opened in binary mode.

    // pFile = fopen(fname, "w");
    pFile = fopen(fname, "wb");
    
  2. Cast to char * pointer before indexing. Original code indexes by the sizeof(pData[itr]). [Edit] and then dereferenced the type - then tries to cast to unsigned char @R Sahu

    //fputc((unsigned char)*((&pData[itr])+ptr), pFile);
    unsigned char *p = (unsigned char *) (&pData[itr]);
    fputc(p[ptr], pFile);
    
  3. As @R Sahu pointed out: fclose() should be moved outside the loops.

Minor:

  1. Recommend passing NUM is as argument to save().

  2. foo_t bar[NUM]; is not fully initialized.

  3. The non-loop solution is

    if (fwrite(pData, sizeof(*pData), NUM, pFile) == NUM) Success();
    
  4. Suggest making const: `int Save(const foo_t* pData)

  5. Better to use size_t for ptr & itr

Upvotes: 1

R Sahu
R Sahu

Reputation: 206717

Problem 1

Use the right mode for opening the file.

pFile = fopen(fname, "wb");

Problem 2

The call to fclose is in the wrong place.

for (itr = 0; itr<NUM; itr++) {
  for (ptr=0; ptr<sizeof(foo_t); ptr++)
  {
    fputc((unsigned char)*((&pData[itr])+ptr), pFile);
  }
  fclose(pFile);
}

You are closing the file after writing out the data of the first foo_t. Subsequent calls will result in undefined behavior since you will be calling fputc using a FILE* that has been closed.

The call to fclose must be moved out of the loops.

for (itr = 0; itr<NUM; itr++) {
  for (ptr=0; ptr<sizeof(foo_t); ptr++)
  {
    fputc((unsigned char)*((&pData[itr])+ptr), pFile);
  }
}
fclose(pFile);

Problem 3

The way you are trying to access a byte in the loops is incorrect. Here are the loops:

for (itr = 0; itr<NUM; itr++) {
  for (ptr=0; ptr<sizeof(foo_t); ptr++)
  {
    fputc((unsigned char)*((&pData[itr])+ptr), pFile);
  }
}

Here's the line you are trying to get a byte.

    fputc((unsigned char)*((&pData[itr])+ptr), pFile);
                           ^           ^
                           This is of type `foo_t*`

    fputc((unsigned char)*((&pData[itr])+ptr), pFile);
                          ^                 ^
                          This pointer arithmetic is done on `foo_t*`.
                          It is not pointer arithmetic done on `char*`.
                          You are going to run into out of bound memory access
                          very quickly.

    fputc((unsigned char)*((&pData[itr])+ptr), pFile);
                         ^                  ^
                         This is dereferencing a `foo_t*`, which
                         means it is of type `foo_t`.

You are getting the compiler error since you are trying to cast a foo_t to an unsigned char.

To save a foo_t, you can take two approaches. You can use fwrite to save an entire foo_t in one call.

for (itr = 0; itr<NUM; itr++) {
  fwrite(&(pData[itr]), sizeof(foo_t), 1, pFile);
}

If you must write each byte using fputc, which I don't think is needed, you will have to change your code a little bit.

The following should work:

for (itr = 0; itr<NUM; itr++) {
  cp = (char*)&pData[itr];  // Declare char* cp in the function.
  for (ptr=0; ptr<sizeof(foo_t); ptr++)
  {
    fputc(cp[ptr], pFile);
  }
}

Upvotes: 2

Adarsh
Adarsh

Reputation: 893

To write into the binary file you need to open the file in w+b mode. and then use fwrite to write into the file. It should work.

pFile = fopen(fname, "w+b");

Instead of fputc use fwrite.

fwrite ((foo_t *)&pData[itr], sizeof(foo_t), 1, pFile);

Upvotes: 1

Jason Hu
Jason Hu

Reputation: 6333

i think all you need to do is just write it.

foo_t fooarry[SOME_SIZE];

fd = open(fname, O_WRONLY);
write(fd, fooarry, SOME_SIZE * sizeof(foo_t));

UPDATE: if you want to use file stream, go like this:

fwrite(fooarry, siezeof(foo_t), SOME_SIZE, pFile);

Upvotes: 0

Related Questions