Как прочитать большой кусок данных с помощью fread и получить к ним доступ как к массиву в C

У меня есть код с целью чтения двоичного файла с использованием fread, а затем обработки данных и отправки их в char *buffer размером 1310720

На данный момент (с моим рабочим кодом) я считывал файл побайтно для выполнения некоторой обработки, а затем записывал байт 1 на 1 в unsigned char array[i] Я использовал что-то вроде этого

void read_input_file(FILE *stream,char *buffer)
{
    long i = 0;
    unsigned char tmp_buf[1310720] ;
    unsigned char *calc = malloc(1);
    while(i < 1310720)
    {
        fread(calc,1,1,stream);
        tmp_buf[i] = round(*calc /128);//this is an example
        i++;
    }
    
    memcpy(buffer, &tmp_buf[0], 1310720);
}

это работало, но теперь я хочу (по соображениям производительности) прочитать фрагмент данных, размер которого равен размеру буфера. Итак, я попытался использовать что-то вроде этого:

void read_input_file(FILE *stream,char *buffer)
{
    long i = 0;
    unsigned char tmp_buf[1310720] ;
    unsigned char *calc = malloc(1310720);

    fread(calc,1310720,1,stream);

    while(i < 1310720)
    {
        tmp_buf[i] = round(calc[i] /128);//this is an example
        i++;
    }
    
    memcpy(buffer, &tmp_buf[0], 1310720);
}

но что бы я ни делал, я получил ошибку выполнения, когда программа вылетает. Я пробовал много разных вещей и кодов, но ничего не работает.

Итак, как мне прочитать большой кусок данных в буфер, а затем получить к нему доступ побайтно для обработки данных?

Что происходит с кодом внизу? В чем проблема?

Özgür Güzeldereli 20.10.2022 16:41

Вопросы, требующие помощи в отладке, как правило, должны предоставлять минимальный воспроизводимый пример проблемы, который включает функцию main и все #include директивы. Это позволяет другим людям легко тестировать вашу программу, просто используя копирование и вставку.

Andreas Wenzel 20.10.2022 16:41

Вы на винде? Ограничение размера стека в Windows составляет 1024 КБ (1 МБ), и вы пытаетесь создать в стеке буфер размером 1280 КБ. Используйте динамическое выделение памяти дважды. Даже в Unix-подобных системах ограничение размера стека обычно составляет 8 МБ, поэтому выделение такого большого массива в стеке немного сомнительно.

Jonathan Leffler 20.10.2022 16:43

Вы также теряете память в показанном коде — вы не освобождаете calc перед возвратом. Я предполагаю, что отсутствие проверки ошибок связано с упрощением кода для SO, но не пропускайте проверку ошибок (на malloc() и fread()) в вашем реальном коде. И зачем использовать промежуточный буфер? Почему бы просто не скопировать обработанные данные байт за байтом в выходной буфер? Одной из причин может быть «целостность транзакций». Если что-то пойдет не так, вы вообще не захотите изменять buffer. Тогда промежуточный результат является разумным. Вы также должны передать размер буфера в качестве параметра функции для проверки.

Jonathan Leffler 20.10.2022 16:46

в чем смысл tmp_buf? Разве вы не можете читать прямо в buffer?

gog 20.10.2022 16:49

да я на винде (бесплатно я забываю об этом на примере кода)

vrunk11 20.10.2022 16:54

@gog цель tmp_buf — хранить обработанные данные

vrunk11 20.10.2022 16:56

мне нужно сделать это в 2 шага, потому что я отправляю все данные на устройство с libusb, поэтому я отключаю memcpy tmp_buf, когда массив заполнен (я работаю на форке, поэтому я только редактирую данные перед отправка в буфер)

vrunk11 20.10.2022 17:10
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
8
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Поскольку вы говорите, что работаете над Windows , проблема заключается в том, что я обозначил в своем комментарии:

Ограничение размера стека в Windows составляет 1024 КБ (1 МБ), и вы пытаетесь создать в стеке буфер размером 1280 КБ. Используйте динамическое выделение памяти дважды. Даже в Unix-подобных системах ограничение размера стека обычно составляет 8 МБ, поэтому выделение такого большого массива в стеке немного сомнительно.

Поскольку ваша переменная tmp_buf создается как локальная переменная в стеке, вы разрушаете стек в Windows. И в качестве

Я думаю, что ваша функция должна возвращать статус, чтобы указать, была ли она успешной или нет, поэтому я изменил тип возвращаемого значения на int и использую 0 для обозначения успеха и -1 для отказа.

Это означает, что ваш код должен стать более похожим на:

enum { BUFFER_SIZE = 1310720 };

int read_input_file(FILE *stream, char *buffer)
{
    long i = 0;
    unsigned char *temp = malloc(BUFFER_SIZE);
    unsigned char *calc = malloc(BUFFER_SIZE);

    if (temp == NULL || calc == NULL)
    {
        free(temp);   // Free both in case only one was allocated
        free(calc);
        return -1;
    }

    if (fread(calc, BUFFER_SIZE, 1, stream) != 1)
    {
        free(temp);
        free(calc);
        return -1;
    }


    for (size_t i = 0; i < BUFFER_SIZE; i++)
    {
        temp[i] = round(calc[i] / 128);  //this is an example
    }
    
    memcpy(buffer, temp, BUFFER_SIZE);
    free(temp);
    free(calc);
    return 0;
}

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

Также не ясно, что вы не можете избавиться от temp (также известного как tmp_buf), используя:

calc[i] = round(calc[i] / 128.0);

Обратите внимание на преобразование в константу с плавающей запятой; в противном случае округлять нечего, так как деление будет целочисленным. Однако, если в вычислении, отличном от примера, используются другие элементы calc, а не только calc[i], вам понадобится второй массив для хранения результатов.

Спасибо за помощь, которая теперь работает нормально, также не знала о делении с плавающей запятой, и да, я использую другой элемент calc, поэтому нужен временный буфер :)

vrunk11 21.10.2022 16:30

Другие вопросы по теме