Пара наблюдаемых и кажущихся проблем для вас:
(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()
, но здесь это для ясности не указано.