fread' и fwrite' на структура, която съдържа указатели

gcc (GCC) 4.7.0
c89

Здравейте,

Имам следната структура, която се опитвам да напиша и да се страхувам.

Въпреки това, тъй като моето устройство и ресурс са указатели. Fwrite ще прочете стойностите на указателя, а не данните. Не мога да използвам масив за устройството или ресурса. Само указатели, тъй като те трябва да бъдат динамично разпределени.

Разпределям цялата памет за структурните елементи, преди да пиша. Не е показано тук, тъй като искам да запазя фрагмента кратък. Нито освобождаване.

В моята функция fread разпределям паметта за устройството и ресурса, така че fread да чете в тези места в паметта. Това обаче няма да работи.

Кой е най-добрият начин да направите това?

Много благодаря за всеки съвет,

struct data {
    int id;
    int set;
    char *device;
    char *resource;
};

struct database {
    struct data **db_data;
    size_t database_rows;
    size_t database_data_size;
};

int database_write(FILE *fp, const struct database *db)
{
    rewind(fp);

    if(fwrite(*db->db_data, sizeof(struct data), 1, fp) == -1) {
        return DATABASE_ERROR;
    }

    return 0;
}

struct database* database_read(FILE *fp, size_t db_rows, size_t db_data_size)
{
    struct database *db = NULL;
    size_t i = 0;

    db = malloc(sizeof(struct database));

    db->database_rows = db_rows;
    db->database_data_size = db_data_size;
    db->db_data = malloc(sizeof(struct data) * db_rows);

    for(i = 0; i < db_rows; i++) {
        db->db_data[i] = malloc(sizeof(struct data));
        db->db_data[i]->device = malloc(db_data_size);
        db->db_data[i]->resource = malloc(db_data_size);
    }

    rewind(fp);

    if(fread(*db->db_data, sizeof(struct data), 1, fp) == -1) {
        return NULL;
    }

    return db;
}

person ant2009    schedule 25.09.2012    source източник
comment
Това няма да работи - защо не?   -  person Kerrek SB    schedule 25.09.2012


Отговори (3)


Изглежда, че сте отговорили на собствения си въпрос, fread и fwrite просто погледнете какво има в паметта и го поставете във файла. Това работи чудесно, ако пишете неща, които нямат указатели (напр. големи масиви от числа). Не е проектиран да пише структури с указатели.

Ако този файл има формат, трябва да направите това, което форматът казва. Ако измисляте формат, докато вървите, тогава трябва да запишете всеки член един по един във файла. Ще ви трябва някакъв вид буфер, в който да четете (може да се наложи да преоразмерите това, ако нямате спецификация за максимална дължина). Също така, вашата функция database_write също ще трябва да бъде променена доста.

person CrazyCasta    schedule 25.09.2012

Ако device и resource могат да имат променлива дължина, трябва да запишете размера на device и след това данните. Направете същото за resource. Когато ги прочетете обратно, можете да прочетете размера, след това да разпределите памет и накрая да прочетете стойността.

person Klas Lindbäck    schedule 25.09.2012

Вие сами описахте проблема си. fwrite ще напише адреса, а не стойността.

Може би можете да използвате поле за дължината на устройството и ресурса във вашата структура "struct data". Създайте обвивка за fread() и fwrite(), която чете/записва тази дължина. В тази обвивка можете да memcpy устройства, ресурс във временен буфер и да използвате fwrite() върху него.

Това е просто и много основно решение.

Докато изпращате пакети в мрежите, обикновено ще видите структури, съдържащи символни указатели. Първите 4/8 байта съхраняват дължината на данните, а останалите байтове съдържат действителните данни. Потребителят, който чете пакета, първо прочита началото на 4/8 байта. В зависимост от това се издава извикване read() за четене на останалите данни.

Може да се обърнете към хакването на структура технически недефинирано поведение ли е?

person Manik Sidana    schedule 25.09.2012