fgets останавливается перед чтением до конца csv, и выводится неверно - PullRequest
0 голосов
/ 27 сентября 2019

Я использую fgets для чтения csv, который имеет 100000 строк.

int** readCsv(char *str) {

    char file_name[100];
    strcpy (file_name, PATH);
    strcat( file_name, str);
    FILE *fp;
    fp = fopen(file_name, "r");

    if (!fp) {
        fprintf(stderr, "failed to open file for reading\n");
        //return 1;
    }

    char line[MAX_LINE_SIZE];
    int *result = NULL;
    int **arr;
    int len[ROW];
    arr = (int **)malloc(sizeof(int *) * ROW);
    int row = 0;

    while(fgets(line, MAX_LINE_SIZE, fp) != NULL) {
        int column;
        printf("%s\n", line);
        // plus one because the last number did not be added with comma
        column = countComma(line) + 1;
        len[row] = column;
        printf("%d\t", column);
        result = strtok(line, ",");
        arr[row] = (int *)malloc(sizeof(int) * column);
        column = 0;
        while( result != NULL ) {
            arr[row][column] = atoi(result);
            //printf("%d\t", arr[row][column]);
            result = strtok(NULL, ",");
            column++;
        }
        printf("%d\n", row);
        //printf("\n");
        row++;
    }
    fclose (fp);
    return arr;
}

, и он остановился на строке 5256 из 100000. Данные, которые он прочитал, также были неправильными (данные строки 5256первоначально данные строки 5276).Я не знаю, где пошло не так, любая помощь будет принята с благодарностью.Спасибо, ребята!

, где он остановился исходные данные

(я установил MAX_LINE_SIZE на 100000. если эта информация поможет)

1 Ответ

1 голос
/ 28 сентября 2019

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

Гера - это описание проблем, которые я вижу в вашем коде.

Обработка ошибок файла

Поскольку ваша подпрограмма должна возвращать адрес указателя, вы должны возвращать значение NULL при возникновении ошибки.Это сигнализирует вызывающей стороне, которая должна проверять наличие нулей, что что-то пошло не так.Также рассмотрите возможность использования функции perror () .Наряду с отображением сообщения, которое вы предоставляете, оно также добавит текст причины ошибки ввода-вывода.

if (fp)
{
   perror("failed to open file for reading.");
   return NULL;
}

Пример вывода при ошибке открытия:

failed to open file for reading: file not found.

MAX_LINE_SIZE иЗначения ROW

Переменная, используемая для чтения каждой строки, должна иметь размер только самой длинной строки в файле плюс 2 байта, которые представляют терминатор строки и нулевой символ (см. документация fgets ).Не следует устанавливать максимальное количество строк, содержащихся в файле.Вы можете увеличить его, но 100000 слишком велико.Не зная ваших данных, вы должны рассмотреть что-то меньшее, например, 1024. ROW должен быть установлен на макс. Строки, ожидаемые для чтения.

#define MAX_LINE_SIZE 1024
#define ROW 100000

Обработка ошибок распределения

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

arr = (int **)malloc(sizeof(int *) * ROW);
if ( arr == NULL ) return NULL;

и здесь

arr[row] = (int *)malloc(sizeof(int) * column);
if ( arr[row] == NULL ) return NULL;

Обрезать дополнительный символдобавлено fgets ()

Есть много способов сделать это, но вы должны удалить терминатор строки из ваших данных.Ниже приведено одно предложение для этого:

if ( strlen(line) > 0 ) line[strlen(line)-1] = 0;

Группировка операторов

Попробуйте сгруппировать операторы, выполняющие определенную задачу, вместе.Это облегчит чтение вашего кода.

Пример 1. Логика размещения столбцов

column =  countComma(line) +1;
arr[row] = (int *)malloc(sizeof(int) * column);
len[row] = column;

Пример 2. Логика анализа строк

column = 0;
result = strtok(line, ",");
while ( result != NULL ) {
    arr[row][column] = atoi(result);
    //printf("%d\t", arr[row][column]);
    result = strtok(NULL, ",");
    column++;
}

strtok returnвведите

Вы должны были получить предупреждение за это, но «результат» должен быть определен как указатель на символ, а не указатель на int.(см. документация strtok )

char *result = NULL;

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

...