Читать и писать структуру в C - PullRequest
0 голосов
/ 11 мая 2010

У меня есть структура:

typedef struct student
{
        char fname[30];
        char sname[30];
        char tname[30];
        Faculty fac;
        int course;
        char group[10];
        int room;
        int bad;
} Student;

Я прочитал это из файла:

Database * dbOpen(char *fname)
{
        FILE *fp = fopen(fname, "rb");
        List *lst, *temp;
        Student *std;
        Database *db = malloc(sizeof(*db));

        if (!fp)
                return NULL;

        FileNameS = fname;

        std = malloc(sizeof(*std));
        if (!fread(std, sizeof(*std), 1, fp)) {
                db->head = db->tail = NULL;
                return db;
        }

        lst = malloc(sizeof(*lst));
        lst->s = std;
        lst->prev = NULL;
        db->head = lst;
        while (!feof(fp)) {
                fread(std, sizeof(*std), 1, fp); 
                temp = malloc(sizeof(*temp));
                temp->s = std;
                temp->prev = lst;
                lst->next = temp;
                lst = temp;
        }
        lst->next = NULL;
        db->tail = lst;

        fclose(fp);

        return db;
}

И у меня проблема ... При последней записи у меня есть такой указатель файла: `Ф.П. 0x10311448 {_ptr = 0x00344b90«НННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН _ _iobuf *

` И я прочитал последнюю запись 2 раза ...

Сохранить код файла:

void * dbClose(Database *db)
{
        FILE *fp = fopen(FileNameS, "w+b");
        List *lst, *temp;

        lst = db->head;
        while(lst != NULL) {
                fwrite(lst->s, sizeof(*(lst->s)), 1, fp);
                temp = lst;
                lst = lst->next;
                free(temp);
        }
        free(db);
        fclose(fp);
}

Ответы [ 4 ]

2 голосов
/ 11 мая 2010

Пара наблюдаемых и кажущихся проблем для вас:

(1) Что если длина вашего файла в байтах не кратна sizeof(Student)? Тогда этот код:

while (!feof(fp)) {
    fread(std, sizeof(*std), 1, fp);
    ...

может прочитать частичную структуру в память, указанную std. Содержимое std будет частично заполнено и может оставить неопределенную строку C в памяти.

Вы должны проверить возвращаемое значение fread().

(2) Это более важный вопрос. Вы повторно используете память, выделенную и на которую указывает std, хотя вы храните указатель в каждом элементе вашего связанного списка.

Похоже, вы намеревались бы выделить новую память для каждой записи Student. В этом случае вы должны вызвать malloc() в теле цикла, который читает несколько записей из файла.

Эта ошибка также зависит от длины файла - файл должен содержать более одной записи.

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

(4) Вы можете рассмотреть возможность использования calloc(), чтобы обеспечить инициализацию всех записей Student.

Вот так:

Database * dbOpen(char *fname)
{
    FILE *fp = fopen(fname, "rb");
    List *lst, *temp;
    Student *std;
    Database *db = NULL;

    if (!fp)
            return db;

    FileNameS = fname;

    db = malloc(sizeof(*db));
    db->head = NULL;
    lst = NULL;
    while (!feof(fp)) {
            std = malloc(sizeof(*std));
            if (!fread(std, sizeof(*std), 1, fp))
            {
                free(std);
                fprintf(stderr, "Input file concludes in partial record.\n");
                break;
            }

            temp = malloc(sizeof(*temp));
            temp->s = std;
            temp->prev = lst;
            temp->next = NULL;

            if (lst == NULL)
                db->head = temp;
            else
                lst->next = temp;
            lst = temp;
    }
    assert(lst->next == NULL ); /* Now performed above by temp->next assignement. */
    db->tail = lst;

    fclose(fp);

    return db;
}

Я не компилировал и не тестировал вышеуказанный код, но он должен быть близок к работе. Обратите внимание, как добавляется особый случай для инициализации db->head (первый раз в цикле, когда lst равен NULL ), в противном случае предыдущий элемент списка связан с вновь добавленным элементом (более поздние итерации). Конечно, мы также должны проверять возвращаемые значения из malloc(), но здесь это для ясности не указано.

1 голос
/ 12 мая 2010

Это выделяется для меня:

while (!feof(fp)) { 
            fread(std, sizeof(*std), 1, fp);  
            temp = malloc(sizeof(*temp)); 
            temp->s = std; 
            temp->prev = lst; 
            lst->next = temp; 
            lst = temp; 
        } 

Не следует использовать feof() в качестве условия цикла; индикатор конца файла не устанавливается до тех пор, пока после не будет предпринята попытка чтения за концом файла, поэтому ваш цикл будет выполняться слишком много раз. Перестройте цикл, чтобы использовать возвращаемое значение fread(), и проверяйте по feof() только в случае сбоя fread():

while (fread(std, sizeof *std, 1, fp) == 1)
{
  temp = malloc(sizeof *temp);
  temp->s = std;
  ...
}
if (feof(fp)) 
  // handle end of file
else
  // handle other read error
0 голосов
/ 11 мая 2010

В этом цикле:

    while (!feof(fp)) {
            fread(std, sizeof(*std), 1, fp); 
            temp = malloc(sizeof(*temp));
            temp->s = std;
            temp->prev = lst;
            lst->next = temp;
            lst = temp;
    }

вы используете результат fread, не проверяя, что он вернулся успешно. Вы должны проверить feof(fp) или возвращаемое значение fread, прежде чем предположить, что данные были успешно прочитаны.

0 голосов
/ 11 мая 2010

Первый проход, пока не копая слишком глубоко, я бы сказал, что вы написали, что вы прошли конец своей записи. Вывод, который вы показываете, во многом похож на вывод отладочной памяти, который вы бы видели в конце буфера malloc. Возможно, ваша база данных выровнена не совсем правильно? Глядя еще немного сейчас ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...