LINUX.ORG.RU

Размер структуры с вложенным массивом структур

 ,


0

1
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#define MAX_DATA 512

struct Child {
    int id;
    int set;
    char name[MAX_DATA];
    char email[MAX_DATA];
};

struct Database {
    int max_rows;
    int max_data;
    struct Child *rows;
};

struct Child *
Allocate_childs(int max_rows)
{
    struct Child *rows = malloc(max_rows * sizeof(struct Child));
    assert(rows != NULL);
    return rows;
}

struct Database *
Allocate_database(int max_rows)
{
    struct Database *db = malloc(max_rows * sizeof(struct Child) + sizeof(struct Database));
    assert(db != NULL);
    return db;
}

int main(int argc, char *argv[])
{
    int max_rows = 100;

    if (argc > 1) {
        max_rows = atoi(argv[1]);
    }

    struct Child *rows = Allocate_childs(max_rows);
    struct Database *db = Allocate_database(max_rows);
    db->rows = rows;
    db->max_rows = max_rows;

    printf("sizeof rows: %lu\n", sizeof(*rows));
    printf("sizeof db: %lu\n", sizeof(*db));
    printf("sizeof db (correct?): %lu\n", sizeof(*db) + sizeof(*rows));

    return 0;
}

Правильно ли я понял, что sizeof() в коде выше выдает не то, что я желаю и надо считать ручками? Т.е. верно считать sizeof(*db) + sizeof(*rows). Или может я что-то не понял? Нужно создавать структуры с динамическим массивом другой структуры. Погуглил, но ответа точного не нашел. Про VLA знаю, но пока хочу сделать все по-старинке.

Ответ на: комментарий от gh0stwizard

А вообще у этого кода небольшой смелл. read_database принимает struct Database *db, который либо инициализирован, либо нет. В первом случае это означает, что ранее была проведена бесполезная работа по выделению rows. Во втором, что содержимому db вообще доверять нельзя, и это классический инициализатор. Судя по free(db->rows) это первый случай.

Обычаи таковы, что конструктор возвращает свежий уникальный объект (который сделал сам), а инициализатор никогда не смотрит в содержимое переданного указателя, т.к. оно может быть мусором, и это чревато сегфолтом.

зы. не заметил поначалу, что free() добавился.

arturpub ★★ ()
Ответ на: комментарий от arturpub

Я переделал read_database чтобы он возращал ссылку на структуру. Во-первых, сократилось выделение памяти, во-вторых, старые данные не нужно занулять, а если подсунут другой файл с другим размером rows_size, то все будет чики-пуки. Вот ее код:

struct Database *
read_database(const char *filename)
{
    FILE *fp;
    int rc = 0;
    struct Database *db = malloc(sizeof(*db));

    assert(db);

    fp = fopen(filename, "r+b");
    assert(fp);

    rc = fread(db, sizeof(*db), 1, fp);
    assert(rc == 1);

    // refresh
    db->rows = calloc(db->rows_size, sizeof(db->rows[0]));

    rc = fread(db->rows, sizeof(db->rows[0]), db->rows_size, fp);
    assert(rc == db->rows_size);

    rc = fclose(fp);
    assert(rc != EOF);

    return db;
}
С учетом этого, поставленные задачи решаются. Когда создается файл БД используем один вариант (make_database), для других функций программы (чтение, изменение строк) используется read_database().

P.S. Имя для нее лучше взять open_database(), но не суть.

gh0stwizard ★★★★★ ()
Последнее исправление: gh0stwizard (всего исправлений: 1)
Ответ на: комментарий от invy

дело не в том, нужно или нет, а в том что считается оно в рантайме уже, а не при компиляции.

вы так говорите, как будто-бы в этом есть что-то хорошее.

emulek ()
Ответ на: комментарий от invy

ну я имел ввиду, что эти ваши новые массивы потому и не нужны, что считаются через задницу. Ну и вообще.

emulek ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.