Структура memcpy, содержащая переменные-указатели на недействительный указатель

у меня такая структура

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

Я хочу скопировать эту структуру в фиксированный блок памяти и записать в файл в двоичном режиме и прочитать эти данные из файла в фиксированный блок памяти. А затем скопировать эти данные с помощью memcpy в структуру.

Как это

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

Я могу записать такие данные, но я не уверен, что memcpy копирует мои переменные-указатели. И я читаю файл, но не работает.

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

Мой полный код находится здесь Нажмите


person johnny003    schedule 27.05.2020    source источник
comment
Поскольку вы отметили C++, вам следует использовать new и delete, а не malloc и free. Функция malloc не вызывает конструктор structs и classes.   -  person Thomas Matthews    schedule 27.05.2020
comment
Вы отметили и C, и C++. Вы смешиваете языки? Помните, что C++ может вводить виртуальные таблицы в структуры. В языке C нет наследования виртуальных методов. Кроме того, в С++ есть std::vector, который похож на массив, который управляет динамической памятью для вас.   -  person Thomas Matthews    schedule 27.05.2020
comment
Я поменял теги. @ThomasMatthews   -  person johnny003    schedule 27.05.2020
comment
При копировании структуры копируются указатели, а не данные. Вам нужно будет скопировать фактическое содержимое, если вы хотите его сохранить.   -  person Sami Kuhmonen    schedule 27.05.2020
comment
Как я могу это сделать ? Скопируйте фактические данные в динамическую память, запишите файл и перечитайте ? @SamiKuhmonen   -  person johnny003    schedule 27.05.2020
comment
То, что вы пытаетесь сделать (сохранить в файле двоичное содержимое структуры в памяти, которая содержит указатели на другие части памяти), не работает. Во-первых, не гарантируется, что сама структура будет правильно передаваться из файла туда и обратно, но, что более важно, указатели/адреса не могут быть сохранены и загружены таким образом, поскольку они существуют только на время выполнения программы. Вы стремитесь к чему-то более сложному, сериализации, что означает написание кода для хранения каждого бита в четко определенном порядке в файле, а затем считывание его обратно.   -  person Ben Zotto    schedule 27.05.2020


Ответы (2)


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

Кажется, что memcpy делает ваш код неудачным. Если вы хотите скопировать структуру, содержащую указатель (или массив), вы должны использовать memcpy для каждого параметра этой структуры. Например, если вы хотите скопировать 256-байтовую структуру для адреса, на который указывает указатель fblock:

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

Если вы хотите скопировать все данные из f1.data_bitmap и f1.node_bitmap в fblock, вы должны выделить для этого указателя не менее 128*sizeof(int) + 20 * sizeof(int) байт.

Аналогично, если вы хотите скопировать данные в структуру f2:

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

Вы можете изменить на:

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

Вы можете увидеть больше информации о копировании структуры: Копирование одной структуры в другую.

Другое дело, вы не должны использовать функцию malloc: ?

Если коду нравится memcpy(fblock,f1.node_bitmap ,20*sizeof(int));, вам не нужно приводить указатель источника и получателя, потому что memcpy не заботится о типе данных, он заботится об адресе источника, адресе назначения и количестве данных, которые вы хотите скопировать.

person Hitokiri    schedule 27.05.2020
comment
Спасибо за ваш подробный ответ. @Хитокири - person johnny003; 27.05.2020

Я хочу скопировать эту структуру в фиксированный блок памяти и записать в файл в двоичном режиме и прочитать эти данные из файла в фиксированный блок памяти. А затем скопировать эти данные с помощью memcpy в структуру.

Вам действительно не нужно создавать промежуточный буфер. Просто читайте/пишите непосредственно в структуру. Вы делаете это, выполняя два чтения или записи для каждой операции "сохранения/восстановления". Иногда это называют «сериализацией».

Это проще и быстрее и не требует memcpy.

Вот ваш код, реорганизованный для этого:

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

ОБНОВЛЕНИЕ:

Я имею в виду, что хочу использовать этот файл как файловую систему. Например, запишите эту структуру в первый блок, а другую структуру во второй блок и размер блока 2 КБ. Поэтому я использую память кучи для фиксации длины данных. Размер файла фиксирован и, например, 1 МБ.

Хорошо, вот версия, которая записывает несколько блоков и сравнивает результаты. Он выравнивает каждый блок размером 2 КБ, используя общий размер 1 МБ:

#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;
}
person Craig Estey    schedule 27.05.2020
comment
Но я хочу записать блок данных в файл. Фиксированная длина. Могу ли я сделать это с помощью этого метода? - person johnny003; 27.05.2020
comment
Я не уверен, что вы имеете в виду. Это записывает структуру в файл фиксированной длины. Возможно, вы могли бы более подробно объяснить, о чем вы думаете, и я мог бы соответствующим образом изменить пример. Я не уверен, как 256 выше влияет на вещи - person Craig Estey; 27.05.2020
comment
Я имею в виду, что хочу использовать этот файл как файловую систему. Например, напишите эту структуру в первый блок, а другую структуру во второй блок и размер блока 2 КБ. Поэтому я использую память кучи для фиксации длины данных. Размер файла фиксированный и 1 МБ, например - person johnny003; 28.05.2020
comment
Спасибо за обновление. Эта версия довольно хороша. Я хочу отметить как ответ как ваш ответ, так и ответ Хитоири. Я могу это сделать ? - person johnny003; 28.05.2020
comment
Вы можете проголосовать за любое количество ответов. Но только один может быть принятым ответом. Вы можете изменить ответ, который является принятым постфактум. См.: stackoverflow.com/help/someone-answers. - person Craig Estey; 28.05.2020