0

I have like this struct

struct free_bitmap{
   int *node_bitmap;
   int *data_bitmap;
}

I want to copy this struct to fixed memory block and write to file with binary mode and read this data from file to fixed memory block.And than copy this data with memcpy to struct.

Like this

struct free_bitmap f1;
struct free_bitmap f2;

f1.node_bitmap = (int *) malloc( sizeof(int) * 20 );
f1.data_bitmap = (int *) malloc( sizeof(int) * 128);

void * fblock = (void *) malloc(256);
memcpy((char*)fblock,(void*) &f1 ,256 );
int fd = open("test",O_RDWR|O_CREAT, 0600);
write(fd,fblock,256);
free(fblock);

I can write the data like this but I'm not sure memcpy is copying my pointer variables.And I read the file but does not work.

 block = (void *) malloc(256);

lseek(fd, 0, SEEK_SET);
read(fd,fblock,256);

f2.node_bitmap = (int *) malloc( sizeof(int) * 20 );
f2.data_bitmap = (int *) malloc( sizeof(int) * 128);

memcpy((void*) &f2 , (char*)fblock , 256 ); 
free(fblock);

for(i=0;20>i;++i)
    printf("%d " ,f1.node_bitmap[i]);

free(f2.node_bitmap);
free(f2.data_bitmap);

My full code is here Click

johnny003
  • 5
  • 7
  • Since you tagged C++, you should be use `new` and `delete`, not `malloc` and `free`. The `malloc` function does not call the constructor of `struct`s and `class`es. – Thomas Matthews May 27 '20 at 19:22
  • You tagged both C and C++. Are you mixing the languages? Remember that C++ may introduce *virtual tables* into structures. The C language has no inheritance of virtual methods. Also, C++ has `std::vector` which is like an array that manages dynamic memory for you. – Thomas Matthews May 27 '20 at 19:23
  • I changed the tags. @ThomasMatthews – johnny003 May 27 '20 at 19:25
  • Copying the struct copies the pointers, not the data. You’ll need to copy the actual contents if you want to save that. – Sami Kuhmonen May 27 '20 at 19:30
  • How can I do that ? Copy the actual data into heap memory and write file and re-read ?@SamiKuhmonen – johnny003 May 27 '20 at 19:32
  • 1
    What you're trying to do (save to a file the binary contents of an in-memory structure, which contains pointers to other parts of memory) doesn't work. In the first instance, the structure itself isn't guaranteed to "round-trip" correctly from a file but more importantly, pointers/addresses can't be saved and loaded like this since they exist only for the duration of the program's execution. You're aiming for something more sophisticated, "serialization", which means writing code to store each bit in a well-defined order in the file and then read that back. – Ben Zotto May 27 '20 at 20:19

2 Answers2

1
memcpy((char*)fblock,(void*) &f1 ,256 );

It seems that the memcpy makes your code failed. If you want to copy the struct that contents pointer (or array), you should use the memcpy for each parameter of this struct. For example, if you want to copy 256 bytes struct to address that pointer fblock points to:

memcpy(fblock,f1.node_bitmap ,20*sizeof(int));
// then copy the `256-20*sizeof(int)` by of `f1.data_bitmap` to `fblock`
memcpy(((uint8_t *))fblock + 20*sizeof(int),f1.data_bitmap ,256-20*sizeof(int));
// Note that, you should initialize the data in f1.data_bitmap before copying

If you want to copy all of data in f1.data_bitmap and f1.node_bitmap, to fblock, you have to allocate at least 128*sizeof(int) + 20 * sizeof(int) bytes for this pointer.

It's similar when you want to copy the data to f2 struct:

memcpy((void*) &f2 , (char*)fblock , 256 ); 

You can change to:

memcpy(f2.node_bitmap, fblock, 20*sizeof(int));
memcpy(f2.data_bitmap, (uint8_t *)fblock + 20*sizeof(int), 256 - 20 *sizeof(int));

You can see more info of copying struct : Copying one structure to another.

Another thing, you should not cast the malloc function: Do I cast the result of malloc?

If the code likes memcpy(fblock,f1.node_bitmap ,20*sizeof(int));, You do not need to cast the source and destination pointer, because memcpy does not care about type of data, it cares about the address of source, address of destination and the amount of data that you want to copy.

Community
  • 1
  • 1
Hitokiri
  • 3,607
  • 1
  • 9
  • 29
1

I want to copy this struct to fixed memory block and write to file with binary mode and read this data from file to fixed memory block.And than copy this data with memcpy to struct.

You really don't need to create an intermediate buffer. Just read/write directly to the struct. You do this by doing two reads or writes for each "save/restore" operation. This is sometimes called a "serialization"

It's simpler and faster and doesn't need memcpy.

Here's your code refactored to do that:

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

enum {
    NODECOUNT = 20,
    DATACOUNT = 128,
};

struct free_bitmap {
    int *node_bitmap;
    int *data_bitmap;
};

void
bitmap_alloc(struct free_bitmap *f)
{

    f->node_bitmap = malloc(sizeof(int) * NODECOUNT);
    f->data_bitmap = malloc(sizeof(int) * DATACOUNT);
}

void
bitmap_free(struct free_bitmap *f)
{

    free(f->node_bitmap);
    free(f->data_bitmap);
}

void
bitmap_write(int fd,struct free_bitmap *f)
{

    write(fd,f->node_bitmap,sizeof(int) * NODECOUNT);
    write(fd,f->data_bitmap,sizeof(int) * DATACOUNT);
}

void
bitmap_read(int fd,struct free_bitmap *f)
{

    read(fd,f->node_bitmap,sizeof(int) * NODECOUNT);
    read(fd,f->data_bitmap,sizeof(int) * DATACOUNT);
}

int
main()
{
    struct free_bitmap f1;
    struct free_bitmap f2;

    bitmap_alloc(&f1);

    int i;

    for (i = 0; i < NODECOUNT; ++i)
        f1.node_bitmap[i] = i;

    int fd = open("test", O_RDWR | O_CREAT, 0600);

    bitmap_write(fd,&f1);

    printf("a");
    lseek(fd, 0, SEEK_SET);

    bitmap_alloc(&f2);
    bitmap_read(fd,&f2);

    for (i = 0; i < NODECOUNT; ++i)
        printf("%d ", f1.node_bitmap[i]);
    printf("\n");

    bitmap_free(&f1);
    bitmap_free(&f2);

    return 0;
}

UPDATE:

I mean I want to use this file like a file system. For example Write this struct to first block and another struct to second block and Block size 2kb.So I use the heap memory to fix data lenght.File size fixed and 1Mb for example

Okay, here's a version that writes multiple blocks and compares the results. It aligns each to a block size of 2KB, using a 1MB total size:

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

enum {
    NODECOUNT = 20,
    DATACOUNT = 128,
    BLOCKSIZE = 2 * 1024,
    FILESIZE = 1024 * 1024,
    NMAP = 5,
};

struct free_bitmap {
    int *node_bitmap;
    int *data_bitmap;
};

void
bitmap_alloc(struct free_bitmap *f)
{

    f->node_bitmap = malloc(sizeof(int) * NODECOUNT);
    f->data_bitmap = malloc(sizeof(int) * DATACOUNT);
}

void
bitmap_free(struct free_bitmap *f)
{

    free(f->node_bitmap);
    free(f->data_bitmap);
}

void
bitmap_write(int fd,struct free_bitmap *f)
{
    ssize_t tot = 0;

    tot += write(fd,f->node_bitmap,sizeof(int) * NODECOUNT);
    tot += write(fd,f->data_bitmap,sizeof(int) * DATACOUNT);

    tot = BLOCKSIZE - tot;
    if (tot > 0)
        lseek(fd,tot,SEEK_CUR);
}

void
bitmap_read(int fd,struct free_bitmap *f)
{
    ssize_t tot = 0;

    tot += read(fd,f->node_bitmap,sizeof(int) * NODECOUNT);
    tot += read(fd,f->data_bitmap,sizeof(int) * DATACOUNT);

    tot = BLOCKSIZE - tot;
    if (tot > 0)
        lseek(fd,tot,SEEK_CUR);
}

int
mapcmp(int mapidx,const char *tag,const int *lhs,const int *rhs,int count)
{
    int i;
    int bad = 0;

    for (i = 0;  i < count;  ++i) {
        if (lhs[i] != rhs[i]) {
            printf("mapcmp: MISMATCH mapidx=%d tag=%s i=%d lhs=%d rhs=%d\n",
                mapidx,tag,i,lhs,rhs);
            bad = 1;
        }
    }

    return bad;
}

int
main(void)
{
    struct free_bitmap wlist[NMAP];
    struct free_bitmap *wcur;
    struct free_bitmap rlist[NMAP];
    struct free_bitmap *rcur;
    int off;
    int i;
    int mapidx;
    int code;

    int fd = open("test", O_RDWR | O_CREAT, 0600);
    ftruncate(fd,FILESIZE);

    // create blocks with unique test data
    off = 0;
    for (wcur = &wlist[0];  wcur < &wlist[NMAP];  ++wcur, off += 23) {
        bitmap_alloc(wcur);

        for (i = 0; i < NODECOUNT; ++i)
            wcur->node_bitmap[i] = i + off;

        for (i = 0; i < DATACOUNT; ++i)
            wcur->data_bitmap[i] = i + off + 17;

        bitmap_write(fd,wcur);
    }

    lseek(fd, 0, SEEK_SET);

    for (rcur = &rlist[0];  rcur < &rlist[NMAP];  ++rcur) {
        bitmap_alloc(rcur);
        bitmap_read(fd,rcur);
    }

    code = 0;

    // compare all data in all blocks
    for (mapidx = 0;  mapidx < NMAP;  ++mapidx) {
        wcur = &wlist[mapidx];
        rcur = &rlist[mapidx];

        if (mapcmp(mapidx,"NODE",rcur->node_bitmap,wcur->node_bitmap,NODECOUNT))
            code = 1;

        if (mapcmp(mapidx,"DATA",rcur->data_bitmap,wcur->data_bitmap,DATACOUNT))
            code = 1;
    }

    // release all blocks
    for (mapidx = 0;  mapidx < NMAP;  ++mapidx) {
        bitmap_free(&wlist[mapidx]);
        bitmap_free(&rlist[mapidx]);
    }

    printf("%s\n",code ? "FAIL" : "PASS");

    return code;
}
Craig Estey
  • 30,627
  • 4
  • 24
  • 48
  • But I want to write block of data to file.Fixed lenght. Can I do it with this method ? – johnny003 May 27 '20 at 20:49
  • I'm not sure what you mean by this. This does write the struct to a file, with fixed length. Perhaps you could explain in some more detail what you're thinking of, and I could adjust the example accordingly. I'm not sure how the `256` above factors into things – Craig Estey May 27 '20 at 20:56
  • I mean I want to use this file like a file system.For examle Write this struct to first block and another struct to second block and Block size 2kb.So I use the heap memory to fix data lenght.File size fixed and 1Mb for example – johnny003 May 27 '20 at 21:25
  • Thank you for update.This version pretty well.I want to mark as answer both your and Hitoiri's answer. Can I do that ? – johnny003 May 28 '20 at 06:12
  • You can _upvote_ as many answers as you want. But only one can be the "accepted" answer. You are able to change which answer is the accepted one after the fact. See: https://stackoverflow.com/help/someone-answers – Craig Estey May 28 '20 at 15:03