код на С убит при чтении 250 МБ файла - PullRequest
2 голосов
/ 07 ноября 2019

Я пытаюсь обработать файл размером 250 МБ, используя скрипт на языке C. Этот файл в основном представляет собой набор данных, и я хочу прочитать только некоторые столбцы и (что более важно) разбить один из них (который изначально является строкой) напоследовательность символов.

Однако, несмотря на то, что у меня достаточно оперативной памяти, код отключается консолью (используя KDE Neon) каждый раз, когда я ее запускаю.

Источник доступен ниже:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {

FILE *arquivo;
char *line = NULL;
size_t len = 0;
int i = 0;
int j;
int k;
char *vetor[500];
int acertos[45];

FILE *licmat = fopen("licmat.csv", "w");

//creating the header
fprintf(licmat,"CO_CATEGAD,CO_UF_CURSO,ACERTO09,ACERTO10,ACERTO11,ACERTO12,ACERTO13,ACERTO14,ACERTO15,ACERTO16,ACERTO17,ACERTO18,ACERTO19,ACERTO20,ACERTO21,ACERTO22,ACERTO23,ACERTO24,ACERTO25,ACERTO26,ACERTO27,ACERTO28,ACERTO29,ACERTO30,ACERTO31,ACERTO32,ACERTO33,ACERTO34,ACERTO35\n");

if ((arquivo = fopen("MICRODADOS_ENADE_2017.csv", "r")) == NULL) {
    printf ("\nError");
    exit(0);
} 

//reading one line at a time
while (getline(&line, &len, arquivo)) {

    char *ptr = strsep(&line,";");
    j=0;
    //breaking the line into a vector based on ;
    while(ptr != NULL)
    {
        vetor[j]=ptr;
        j=j+1;
        ptr = strsep(&line,";");
    }

    //filtering based on content
    if (strcmp(vetor[4],"702")==0 && strcmp(vetor[33],"555")==0) {
        //copying some info
        fprintf(licmat,"%s,%s,",vetor[2],vetor[8]);   
        //breaking the string (32) into isolated characters
        for (k=0;k<27;k=k+1) {
            fprintf(licmat,"%c", vetor[32][k]);
            if (k<26) {
                fprintf(licmat,",");
            }
        }
        fprintf(licmat,"\n");

    }

    i=i+1;
}

free(line);
fclose(arquivo);
fclose(licmat);

}

Вывод безупречен до момента, когда скрипт убит. Выходной файл имеет длину всего 640 КБ и содержит около 10000 строк.

В чем может быть проблема?

1 Ответ

4 голосов
/ 07 ноября 2019

Мне кажется, что вы неправильно обращаетесь с буфером памяти, управляемым getline() - который распределяет / перераспределяет по мере необходимости - с помощью strsep(), который, кажется, манипулирует тем же значением указателя.

Как только line был обновлен, чтобы отразить какой-либо другой элемент в строке, он больше не указывает на начало выделенной памяти, а затем boom в следующий раз, когда getline() нужно что-то с этим делать.

Используйте другую переменную, чтобы перейти к strsep():

while (getline(&line, &len, arquivo) > 0) { // use ">=" if you want blank lines
    char *parseline = line;

    char *ptr = strsep(&parseline,";");
    // do the same thing later

Ключевой момент: вам не разрешено смешивать со значением line, отличным от free() это в конце (что вы делаете), и вы не можете позволить любой другой подпрограмме сделать это.

Редактировать: обновлено, чтобы отразить getline() возвращая <0 в случае ошибки (h / t для @ user3121023) </p>

...