Как создать связанный список из двоичного входного файла? С первыми несколькими байтами, являющимися int, а следующие несколько - с символом и т. Д. - PullRequest
0 голосов
/ 23 марта 2019

Я хочу создать связанный список из входного двоичного файла. Первые байты sizeof (int) - это int, а следующие байты sizeof (char) - это char, и он продолжает работать таким образом. Что я хочу сделать, это создать связанный список из этого файла, где каждый узел в связанном списке содержит символ и узел дерева, содержащий это значение типа int.

Я застрял, когда дело доходит до создания связанного списка из этого файла. Если бы это был обычный файл с целыми числами, без двоичных файлов и без символов, я бы использовал fscanf, чтобы прочитать файл и сохранить его содержимое в массиве, а затем я бы прошел через массив и создал узлы. Тем не менее, я запутался, когда эти символы присутствуют в файле. Может ли кто-нибудь помочь мне и сказать, есть ли способ создать связанный список?

Правки ->

ListNode *head = malloc(sizeof(ListNode)*sizeoffile);

//how do i find the size of the file.
//if it was a file with just integers, I would have done something like this
// int value;
// int count = 0;
//while(fscanf(fptr, "%d", &value)==1)
//{
//  count++;
//}
//But now that there is chars, I am really confused how I would determine  
//the size of the file.

while(!feof(fptr))
{
  fread(head, sizeof(int)+sizeof(char), 1, fptr);
}

I know this is not right. ^

Ответы [ 3 ]

1 голос
/ 24 марта 2019

Шаг 1. Предположим, что все данные из внешнего источника (например, из файла) являются потенциально вредоносными и / или поврежденными и / или получены с другого компьютера (с другим sizeof(int) и другим порядком байтов).

Шаг 2: правильно определите формат файла (с учетом шага 1).Например, возможно, это должно быть значение в диапазоне от 123 до 123456, которое хранится в виде 4 последовательных байтов в порядке с прямым порядком байтов (оно никогда не должно быть int);и, возможно, это байт, содержащий символ ASCII (он никогда не должен быть «случайным, каким бы ни был набор символов, который компилятор чувствовал при использовании char»).

Шаг 3: Напишите некоторый код для загрузки данных из файла вмассив байтов.Если ожидается, что файл будет маленьким, вы можете использовать realloc() для увеличения размера буфера, если буфер был недостаточно большим (но убедитесь, что есть «максимальный размер файла», чтобы злоумышленник не смог обманутьВы потребляете всю доступную оперативную память и зависаете из-за «нехватки памяти»).Если ожидается, что файл будет больше;посмотрите на функции как mmap().Кроме того, вы можете использовать цикл «читать следующую часть файла; анализировать следующую часть файла», который перезагружает буфер фиксированного размера.

Шаг 4: Написать код для анализа данных «массива байтов» и проверить, чтоэто фактически соответствует спецификациям формата файла всеми возможными способами.Например, unsigned long value = buffer[0] + (buffer[1] << 8) + (buffer[2] << 16) + (buffer[3] << 24) и if( (value < 123) || (value > 123456) ) { // Data is malformed.

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

    // Parse and check it

    if(bufferSize < position + 5) {
        return "File ends in the middle of a record";
    }
    unsigned long value = buffer[position] + (buffer[position+1] << 8) + (buffer[position+2] << 16) + (buffer[position+3] << 24);
    if( (value < 123) || (value > 123456) ) {
        return "Data was malformed (integer out of range)";
     }

    if( (buffer[position+4] < 0x20) || (buffer[position+4] >= 0x7F) ) {
        return "Data was malformed (character not printable ASCII)";
    }

    // Create a structure

    myStructureType * myStruct = malloc(sizeof(myStructureType));
    if(myStruct == NULL) {
        return "Failed to allocate memory for structure";
    }
    myStruct->value = value;
    myStruct->character = buffer[position+4];
    position += 5;

    // Add structure to singly linked list

    myStruct->next = NULL;
    if(listFirst == NULL) {
       listFirst =  myStruct;
    } else {
       listLast->next =  myStruct;
    }
    listLast =  myStruct;
0 голосов
/ 24 марта 2019

Хорошо, поэтому я предлагаю вам забыть о связанных списках.Просто придерживайтесь первой проблемы: чтение данных из двоичного файла.

В тексте задачи неясно размер объектов, поэтому предположим, что в нем говорится: «Существует двоичный файл, содержащий виджеты, состоящие из 32-разрядного целого числа (little-endian) и 8-разрядногочисло, представляющее символ ASCII. Сбросьте все виджеты до stdout по одному на строку, представляющую целое число в основании 10, за которым следует пробел, а затем символ ".

Давайте предположим, что ваш int является 32-разряднымendian, а ваш символ - это байт со знаком, т. е. давайте предположим, что вы находитесь на одной из 99,9% машин в мире.

Теперь вам нужно прочитать виджеты, то есть int и char.Обычно при чтении вам нужно выбрать две функции: fscanf и fread.Первый читает данные, отформатированные для чтения человеком, а второй читает байты, как они есть из файла.Какой тебе нужен сейчас?второй, поэтому мы должны использовать это.

В своем коде вы пишете

while (!feof(fptr))

Это всегда неправильно .Единственный правильный способ чтения файла:

while (1) {
    // Read
    // Check
    // Use
}

Тогда вы можете найти способ прочитать и проверить условие while, но, поверьте мне: напишите это так в первый раз.

Итак, давайте заполним выше шаблон.Чтобы проверить, удалось ли fread, вам нужно проверить, вернул ли он количество элементов, которые вы запрашивали.

while (1) {
    int i;
    char c;
    // Read
    int ok1 = fread(&i, 4, 1, fptr);
    int ok2 = fread(&c, 1, 1, fptr);
    // Check
    if (ok1 != 1 || ok2 != 1)
        break;
    // Use
    printf("%d %c\n", i, c);
}

Конечно, вы можете упаковать это во время условия, но я не вижу причины для этого.

Теперь я бы проверил это с вашим вкладом и с хорошимотладчик и проверьте, распечатаны ли все данные в файле.Если все в порядке, вы можете перейти к остальной части проблемы, то есть поместить эти виджеты в связанный список.

Здесь я предположил, что вы еще не изучили struct с.Если это не так, вы можете работать с ними:

struct widget {
    int i;
    char c;
};

[...]

while (1) {
    struct widget w;
    // Read
    int ok1 = fread(&w.i, 4, 1, fptr);
    int ok2 = fread(&w.c, 1, 1, fptr);
    // Check
    if (ok1 != 1 || ok2 != 1)
        break;
    // Use
    printf("%d %c\n", w.i, w.c);
}

Не обманывайтесь тем фактом, что виджет имеет такую ​​же структуру ваших данных в файле.Вы не можете поверить, что

fread(&w, 5, 1, fptr); // No! Don't do this

правильно прочитает ваши данные.При создании структуры компилятор может поместить все необходимое пространство между полями, поэтому я не удивлюсь, если sizeof(widget) вернет 8.

Отказ от ответственности: я написал код прямо в браузереи не проверял!

0 голосов
/ 23 марта 2019

Я думаю, вы слишком увлечены чем-то, что на самом деле не является фундаментальной проблемой. если вам нужно создать связанный список из файла, вы можете использовать fscanf() или fread() или что угодно, чтобы прочитать файл в буфер и манипулировать этим буфером по своему усмотрению. Та же самая логика для разбора массива целых чисел (считанных из файла) может быть применена для разбора буфера строк из двоичного файла (вы говорите двоичный файл с sizeof(int), sizeof(char) последовательно, поэтому я собираюсь предположить, Вы имеете в виду, что это может быть прочитано в буфер)

Вы говорите

"Если бы это был обычный файл с целыми числами, без двоичного кода и без символов, я использовал бы fscanf, чтобы прочитать файл и сохранить его содержимое в массив, и тогда я бы прошел через массив и сделал узлы "

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

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