Как мне исправить этот метод чтения структур и помещения их в связанный список? - PullRequest
1 голос
/ 18 июня 2020

Мне нужно прочитать файл и поместить его в структуру в двусвязном списке.

Но мой метод не работает int insert_File(List* pointer_to_pointer). Кто-нибудь может помочь? Как я могу это исправить? Как прочитать этот файл и правильно разместить его в каждой переменной в структуре? Спасибо, ребята.

/* ListStudent.h */

struct student
{
    char name[30];
    int cod_student;
    float test_1, test_2, activity, test_optional; /* if test_optional not exist in list_students.txt complete with 0 in struct */
}; 

typedef struct element* List;

int insert_File(List* pointer_to_pointer);
/* ListStudent.cpp */

struct element
{
    struct element *previous;
    struct student database;
    struct element *next;
};

int insert_File(List* pointer_to_pointer)
{
   if(pointer_to_pointer == NULL)
        return 0;

    element *node = *pointer_to_pointer;

    FILE *pointer_to_file;

    struct student s;

    pointer_to_file = fopen("list_students", "r");

    if(NULL == pointer_to_file)
    {
        cout << "ERROR";
        return 1;
    }

    while(fread(&s, sizeof(struct student), 1, pointer_to_file))
    {
        int a = insert_list_sorted_ascending_by_name(pointer_to_pointer, s);
    }
    fclose(pointer_to_file);
    return 0;
}

/* ListStudent_main.cpp */

#include "ListStudent.cpp"

int main(){

List *pointer_to_pointer;

pointer_to_pointer = create_list();

int f = insert_File(pointer_to_pointer);

return 0;
}

Файл txt

Marcos David 885487 9.4 5.4 8.5 0
Victor Corleone 445587 9.8 5.7 9.5 9
Alban Sernen 115400 8.4 8.4 5.5
Alban Aline 775487 1.4 2.4 1.5 1.1
Alban Victor 905487 2.4 2.6 4.5 1.5

1 Ответ

0 голосов
/ 18 июня 2020

Представление данных в файле отличается от представления данных в памяти.

Хотя, например, значение int в памяти состоит из точного фиксированного количества байтов (обычно четыре на современном оборудовании), числа в тексте состоят из переменной серии байтов. Кроме того, значения байтов не совпадают.

885487 в текстовом файле состоит из байтов 0x38 0x38 0x35 0x34 0x38 0x37, тогда как то же число в памяти (предоставляется 32-битное int) выглядит как 0xEF 0x82 0x0D 0x00 (представление с прямым порядком байтов!).

Размеры других элементов также не совпадают, кроме того, между элементами двоичных данных не будет пробела (0x20).

Для иллюстрации: Данные внутри s после первого звонка на fread(&s, sizeof(struct student), 1, pointer_to_file):

name          == "Marcos David 885487 9.4 5.4 8." // you read EXACTLY 30 chars
cod_student   == 170 926 133 // "5 0\n" interpreted as 32-bit int (little endian)
test_1        == <some value> // "Vict" interpreted as 32-bit float
test_2        == <some value> // "or C" interpreted as 32-bit float
activity      == <some value> // "orle" interpreted as 32-bit float
test_optional == <some value> // "one " interpreted as 32-bit float

Я не прилагал усилий для преобразования символов в фактические значения с плавающей запятой, предположим, что довольно очевидно, что значения не будут теми, которые вы действительно хотели иметь ... Я предполагал, что окончания строки unix - если вы используете windows, то перед \n будет дополнительный символ \r, смещающий символы, используемые для заполнения поплавков, на 1, но этого не произойдет. изменить что-либо при чтении ненужных данных.

Теперь у вас есть два варианта:

  • Либо вы сохраняете учеников уже в двоичном формате (во время записи откройте файл с опцией "wb" , для чтения используйте "rb", чтобы не допустить специальной обработки разрывов строк). Имейте в виду, что файл больше не будет доступен для чтения человеком!

  • Или вам нужно преобразовать текстовые данные в двоичные.

Для последнего варианта я лично прочитал бы файл построчно (C: fgets ; C ++: std :: getline ) и проанализировал бы эти строки самостоятельно.

Вы оказались в неудачной ситуации, когда вы выбрали символ-разделитель для элементов данных, которые также могут встречаться в одном из полей данных: пробел. Если вы измените разделитель полей на что-то другое (например, | - также есть специальные символы-разделители, ASCII 0x1 C - 0x1F, идеально подходит для наших целей при чтении, но их сложно ввести в текстовом редакторе ...) , тогда вы значительно упростите себе жизнь: просто выделите строку этим символом-разделителем и преобразуйте подстроки.

На данный момент вы должны искать в строке первое di git (при условии, что цифры не встречается в имени) и скопируйте символы перед (за исключением последнего пробела) в поле имени. Не забудьте завершить строку нулевым символом.

С этого момента вы можете просто токенизировать, начиная с di git, найденного ранее. В C посмотрите на функцию strtok для токенизации и на strtol и strtof для преобразования.

В C ++ (как вы помечен изначально), существует множество различных способов обработки оставшейся строки (возможно, самый простой способ - использовать std::istringstream).

...