简体   繁体   中英

memcpy struct containing pointer variables to void pointer

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

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.

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM